src/types.c

00001 /* 
00002 Copyright (C) 2004,2005,2006 Piotr Pokora <piotr.pokora@infoglob.pl>
00003 Copyright (C) 2004 Alexander Bokovoy <ab@samba.org>
00004 
00005 This program is free software; you can redistribute it and/or modify it
00006 under the terms of the GNU Lesser General Public License as published
00007 by the Free Software Foundation; either version 2 of the License, or
00008 (at your option) any later version.
00009 
00010 This program is distributed in the hope that it will be useful,
00011 but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 GNU General Public License for more details.
00014 
00015 You should have received a copy of the GNU General Public License
00016 along with this program; if not, write to the Free Software
00017 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018 */
00019 
00020 #include <config.h>
00021 #include <stdlib.h>
00022 #include "midgard/midgard_type.h"
00023 #include "midgard/midgard_object.h"
00024 #include "midgard/midgard_metadata.h"
00025 #include "midgard/query.h"
00026 #include "midgard/midgard_legacy.h"
00027 //#include "midgard/mgderr.h"
00028 #include "midgard/query_builder.h"
00029 #include "midgard/midgard_timestamp.h"
00030 #include "midgard/midgard_datatypes.h"
00031 #include "midgard/midgard_quota.h"
00032 #include "schema.h"
00033 #include "midgard_mysql.h"
00034 #include "midgard/midgard_reflection_property.h"
00035 #include "midgard/midgard_error.h"
00036 #include "midgard_core_object.h"
00037 #include "midgard_core_object_class.h"
00038 
00039 GType _midgard_attachment_type = 0;
00040 
00041 enum {
00042         MIDGARD_PROPERTY_NULL = 0,
00043         MIDGARD_PROPERTY_GUID,
00044         MIDGARD_PROPERTY_SITEGROUP,
00045         MIDGARD_PROPERTY_METADATA
00046 };
00047 
00048 typedef enum {
00049         OBJECT_UPDATE_NONE = 0,
00050         OBJECT_UPDATE_EXPORTED,
00051         OBJECT_UPDATE_IMPORTED
00052 } _ObjectActionUpdate;
00053 
00054 static GParamSpec **_midgard_object_class_paramspec()
00055 {
00056         /* Hardcode MidgardRepligardClass parameters. Those will be inherited with MgdObject 
00057          * and thus do not bother about Midgard basic and core parameters later.
00058          * We also should hardcode these parameters to keep one real Midgard object
00059          * which has "one logic" properties and methods.
00060          */
00061   
00062         /* Last value is 'params[n]+1' */
00063         GParamSpec **params = g_malloc(sizeof(GParamSpec*)*5);
00064         params[0] = g_param_spec_string ("guid", "", "GUID",
00065                         " ", G_PARAM_READWRITE);
00066         params[1] = g_param_spec_uint ("sitegroup", "", 
00067                         "Sitegroup which object belongs to. Only for old objects",
00068                         0, G_MAXUINT32, 0, G_PARAM_READWRITE); 
00069         params[2] = g_param_spec_object ("metadata", "",
00070                         "Property with Midgard metadata object",
00071                         G_TYPE_OBJECT, G_PARAM_READWRITE);
00072         params[3] = g_param_spec_string ("action", "", "What was done with object",
00073                         " ", G_PARAM_READWRITE);    
00074         params[4] = NULL;
00075           
00076         return params;     
00077 }
00078 
00079 /* Initialize instance for all types that are not MidgardRepligardClass type. */
00080 static void 
00081 _object_instance_init(GTypeInstance *instance, gpointer g_class)
00082 {
00083     GType own_type = G_TYPE_FROM_INSTANCE(instance);
00084     MgdSchemaTypeAttr *priv = G_TYPE_INSTANCE_GET_PRIVATE (instance, own_type, MgdSchemaTypeAttr);
00085 
00086     MgdObject *self = (MgdObject *) instance;
00087 
00088     self->private = g_new0(MidgardTypePrivate, 1);
00089     self->private->guid = NULL;
00090     self->private->sg = -1;
00091     self->private->action = NULL;
00092     self->private->exported = NULL;
00093     self->private->imported = NULL;
00094     
00095     /* Initialize metadata object */
00096     self->metadata = (MidgardMetadata *) g_object_new(MIDGARD_TYPE_METADATA, NULL);
00097     /* LEAK! */
00098     /* Piotras: I do not understand this, there is object_unref call for metadata
00099      * object in MgdObject finalize. I am completely blind here */ 
00100     
00101     self->private->parameters = NULL;   
00102     self->private->_params = NULL;
00103         
00104     priv->base_index = 1;
00105     
00106     guint propn;
00107     GParamSpec **props =
00108         g_object_class_list_properties(g_type_class_peek(own_type), &propn);
00109     g_free(props);
00110     
00111     priv->num_properties = propn;
00112 
00113     /* g_debug("New object instance for class '%s'", g_type_name(own_type)); */
00114   
00115     /* TODO 
00116      * Add functionality to get properties from self class instead of looking 
00117      * for cached type. We can not store GTypeInfo structure in MgdSchema as this require making 
00118      * schema real global value.
00119      */ 
00120  
00121     /* Allocate properties storage for this instance  */
00122     priv->properties = 
00123         priv->num_properties ? g_new0 (MgdSchemaPropertyAttr*, priv->num_properties) : NULL;
00124     if (priv->properties) {
00125         guint idx;
00126         for (idx = 0; idx < priv->num_properties; idx++) {
00127             priv->properties[idx] = g_new0 (MgdSchemaPropertyAttr, 1);
00128         }
00129     }
00130 }
00131                 
00132 /* AB: This is shortcut macro for traversing through class hierarchy (from child to ancestor)
00133  * until we reach GObject. On each iteration we fetch private data storage for the object
00134  * according to the current class type and run supplied code.
00135  * This allows us to implement dynamic subclassing cast which is done usually via compiled 
00136  * time structure casts in appropriate class-specific hooks for each class in a hierarchy.
00137  * As our object classes have the same structure at each level of inheritance, we are able
00138  * to use the same triple of functions for get_property(), set_property(), and finalize()
00139  * for each class.
00140  */
00141 #define G_MIDGARD_LOOP_HIERARCHY_START              \
00142   do {                      \
00143                           \
00144     priv = G_TYPE_INSTANCE_GET_PRIVATE (object, current_type, MgdSchemaTypeAttr);  \
00145 
00146 #define G_MIDGARD_LOOP_HIERARCHY_STOP             \
00147   current_type = g_type_parent(current_type);           \
00148   } while (current_type != G_TYPE_OBJECT);
00149 
00150 
00151 
00152 /* AB: Handle property assignments. Despite its simplicity, this is *very* important function */
00153 static void
00154 _object_set_property (GObject *object, guint prop_id, 
00155     const GValue *value, GParamSpec   *pspec)
00156 {       
00157         gint prop_id_local = 0;
00158         MgdSchemaTypeAttr *priv;
00159         GType current_type = G_TYPE_FROM_INSTANCE(object);
00160         MgdObject *self = (MgdObject *) object;
00161         MgdSchemaPropertyAttr *prop;
00162 
00163         switch(prop_id) {
00164                         
00165                 case MIDGARD_PROPERTY_GUID:
00166                         g_free ((gchar *)self->private->guid);
00167                         self->private->guid = g_value_dup_string (value);
00168                         break;
00169                 
00170                 case MIDGARD_PROPERTY_SITEGROUP:
00171                         self->private->sg = g_value_get_uint(value);
00172                         break;
00173                 
00174                 case MIDGARD_PROPERTY_METADATA:
00175                         self->metadata = g_value_get_object (value);
00176                         break;
00177                         
00178                 default:
00179                         G_MIDGARD_LOOP_HIERARCHY_START
00180                                 prop_id_local = prop_id - priv->base_index - 1;
00181                         if ((prop_id_local >= 0) && (prop_id_local < priv->num_properties)) {
00182                                 if (priv->num_properties) {
00183                                         prop = priv->properties[prop_id_local];
00184                                         if (!G_IS_VALUE(&prop->value)) {
00185                                                 g_value_init(&prop->value, G_VALUE_TYPE(value));
00186                                                 /* g_debug(" Set property %s", pspec->name );  */
00187                                         }
00188                                         g_value_copy(value, &prop->value);
00189                                 }
00190                                 return;
00191                         }
00192                         G_MIDGARD_LOOP_HIERARCHY_STOP
00193         }
00194 }
00195 
00196 /* Get object's property */
00197 static void
00198 _object_get_property (GObject *object, guint prop_id,
00199                 GValue *value, GParamSpec   *pspec)
00200 {
00201         gint prop_id_local = 0;
00202         MgdSchemaTypeAttr *priv;
00203         GType current_type = G_TYPE_FROM_INSTANCE(object);
00204         MgdObject *self = (MgdObject *) object;
00205 
00206         switch(prop_id) {
00207 
00208                 case MIDGARD_PROPERTY_GUID:
00209                         g_value_set_string (value, self->private->guid);
00210                         break;
00211                 
00212                 case MIDGARD_PROPERTY_SITEGROUP:
00213                         g_value_set_uint (value, (guint)self->private->sg);
00214                         break;
00215                 
00216                 case MIDGARD_PROPERTY_METADATA:
00217                         g_value_set_object(value,
00218                                         (MidgardMetadata *) self->metadata);
00219                         break;
00220                 
00221                 default:
00222                         G_MIDGARD_LOOP_HIERARCHY_START
00223                         prop_id_local = prop_id - priv->base_index - 1;
00224                         if ((prop_id_local >= 0) && (
00225                                                 prop_id_local < priv->num_properties)) {
00226                                 if (priv->num_properties) {
00227                                         if (priv->properties && G_IS_VALUE(
00228                                                                 &priv->properties[prop_id_local]->value)) {
00229                                                 g_value_copy(&priv->properties[prop_id_local]->value, 
00230                                                                 value);
00231                                         }
00232                                 }
00233                                 return;
00234                         }
00235                         G_MIDGARD_LOOP_HIERARCHY_STOP
00236         }
00237 }
00238 
00239 
00240 /* 
00241  * Finalizer for GMidgardObject instance.
00242  * Cleans up all allocated data. As optimization, it handles all data
00243  * which belongs to its ancestors up to but not inluding GObject.
00244  * It is really makes no sense to call this function recursively
00245  * for each ancestor because we already know object's structure.
00246  * For GObject we call its finalizer directly.
00247  */
00248 
00249 static void _object_finalize (GObject *object) 
00250 {
00251         guint idx;
00252         MgdSchemaTypeAttr *priv;
00253         
00254         if(object == NULL)
00255                 return;
00256         
00257         MgdObject *self = (MgdObject *)object;
00258         
00259         /* Free private struct members and MidgardTypePrivate */
00260         g_free((gchar *)self->private->guid); 
00261         g_free((gchar *)self->private->action);
00262         g_free(self->private->exported);
00263         g_free(self->private->imported);
00264         
00265         /* Free object's parameters */
00266         if(self->private->parameters != NULL) {
00267                 
00268                 GSList *_param = self->private->parameters;
00269                 for (; _param; _param = _param->next) {
00270                         g_object_unref(_param->data);   
00271                 }
00272                 g_slist_free(_param);
00273         }
00274 
00275         if(self->private->_params != NULL)
00276                 g_hash_table_destroy(self->private->_params);
00277 
00278         g_free(self->private);
00279 
00280         /* FIXME emmit signal?*/
00281         g_object_run_dispose(G_OBJECT(self->metadata));
00282         g_object_unref(self->metadata);
00283         
00284         GType current_type = G_TYPE_FROM_INSTANCE(object); 
00285         
00286         G_MIDGARD_LOOP_HIERARCHY_START
00287                 for (idx = 0; idx < priv->num_properties; idx++) {
00288                         if (priv->properties[idx]) {
00289                                 if (G_IS_VALUE(&priv->properties[idx]->value)) {
00290                                         g_value_unset(&priv->properties[idx]->value);
00291                                 }
00292                                 g_free (priv->properties[idx]);
00293                                 priv->properties[idx] = NULL;
00294                         }
00295                 }
00296         if (priv->properties) {
00297                 g_free (priv->properties);
00298                 priv->properties = NULL;
00299         }
00300         G_MIDGARD_LOOP_HIERARCHY_STOP
00301                 
00302         /* Call parent's finalizer if it is there */
00303         {
00304                 GObjectClass *parent_class = g_type_class_ref (current_type);           
00305                 if (parent_class->finalize) {
00306                         parent_class->finalize (object);
00307                 }
00308                 g_type_class_unref (parent_class);
00309         }
00310 }
00311 
00312 static GHashTable *_build_create_or_update_query(MgdObject *object)
00313 {
00314         GParamSpec **props;
00315         guint propn, i;
00316         GValue pval = {0,};
00317         GHashTable *sqls = midgard_hash_strings_new();
00318         gchar **table, *sqlset = "", *sqlsetf = "";
00319         const gchar *nick, *strval;
00320         GString *tmpsql;
00321         MidgardObjectClass *klass = MIDGARD_OBJECT_GET_CLASS(object);
00322         const gchar *primary_property = midgard_object_class_get_primary_property(klass);
00323 
00324         if(( props = g_object_class_list_properties(
00325                                         G_OBJECT_GET_CLASS(G_OBJECT(object)), &propn)) == NULL)
00326                 return NULL;
00327 
00328         g_hash_table_insert(sqls, g_strdup(
00329                                 midgard_object_class_get_table(
00330                                         MIDGARD_OBJECT_GET_CLASS(object))), g_strdup(sqlset));
00331         
00332         for (i = 0; i < propn; i++) {
00333                 
00334                 nick =  g_param_spec_get_nick (props[i]);
00335                 
00336                 if ((strlen(nick)) > 0) {
00337                         
00338                         table = g_strsplit_set(nick, ".", 0);
00339                         g_value_init(&pval,props[i]->value_type);
00340                         g_object_get_property(G_OBJECT(object), (gchar*)props[i]->name, &pval);
00341 
00342                         if ((sqlsetf = g_hash_table_lookup(sqls, table[0])) == NULL) {
00343                                 sqlset = g_strdup("");        
00344                                 g_hash_table_insert(sqls, g_strdup(table[0]), sqlset);
00345                         }
00346 
00347                         tmpsql = g_string_new(sqlsetf); 
00348                         
00349                         switch (props[i]->value_type) {
00350                                 
00351                                 case MGD_TYPE_STRING:
00352                                         strval = g_value_get_string(&pval);
00353                                         if(strval == NULL)
00354                                                 strval = "";
00355                                         guint length = strlen(strval);
00356                                         gchar *escaped = g_new(gchar, 2 * length + 1);
00357                                         mysql_real_escape_string(
00358                                                         object->mgd->msql->mysql, 
00359                                                         escaped, strval, length);
00360                                         g_string_append_printf(tmpsql,
00361                                                         "%s='%s', ",
00362                                                         table[1],
00363                                                         escaped);
00364                                         g_free(escaped);
00365                                         break;
00366 
00367                                         
00368                                 case MGD_TYPE_UINT:
00369                                         /* Avoid using primary field with integer type */
00370                                         if(!g_str_equal(props[i]->name, primary_property)) {
00371                                                 g_string_append_printf(tmpsql,
00372                                                                 "%s=%d, ",
00373                                                                 table[1],
00374                                                                 g_value_get_uint(&pval));
00375                                         }
00376                                         break;
00377                                         
00378                                 case MGD_TYPE_INT:
00379                                         if(!g_str_equal(props[i]->name, primary_property)) {
00380                                                 g_string_append_printf(tmpsql,
00381                                                                 "%s=%d, ",
00382                                                                 table[1],
00383                                                                 g_value_get_int(&pval));
00384                                         }
00385                                         break;                                  
00386                                 
00387                                 case MGD_TYPE_FLOAT:
00388                                         g_string_append_printf(tmpsql,
00389                                                         "%s=%f, ",
00390                                                         table[1], 
00391                                                         g_value_get_float(&pval));
00392                                         break;
00393                                 
00394                                 case MGD_TYPE_BOOLEAN:
00395                                         g_string_append_printf(tmpsql,
00396                                                         "%s=%d, ",
00397                                                         table[1],
00398                                                         g_value_get_boolean(&pval));
00399                                         break;                                          
00400                         }
00401 
00402                         g_hash_table_insert(sqls, g_strdup(table[0]), g_string_free(tmpsql, FALSE));
00403                         g_value_unset(&pval);  
00404                         g_strfreev(table);
00405                 }
00406         }
00407         
00408         g_free(props);
00409         return sqls;    
00410 }
00411 
00412 void _insert_records(gpointer key, gpointer value, gpointer userdata)
00413 {
00414         gchar *table = (gchar *) key;
00415         gchar *sql = (gchar *) value;
00416         MgdSchemaTypeQuery *query;
00417         gint qr, rid;
00418         guint object_sitegroup;
00419         MgdObject *object = (MgdObject *) userdata;
00420         /* Get object's sitegroup value. It is set by SG0 admin or from 
00421          * midgard connection handler */
00422         g_object_get(G_OBJECT(object), "sitegroup", &object_sitegroup, NULL);
00423         MidgardObjectClass *klass = MIDGARD_OBJECT_GET_CLASS(object);
00424 
00425         if(!g_str_equal(midgard_object_class_get_table(klass), table)){
00426                 query = g_hash_table_lookup(klass->data->tables, table);
00427                 if (query->use_lang) {
00428                         //langsql = mgd_format(cmo->mobj->mgd, pool,
00429                         //    ", lang=$d ", cmo->mobj->mgd->lang );
00430                         //sqlf = g_strconcat(sql, langsql, NULL);
00431                 }
00432 
00433                 GString *fquery = g_string_new("INSERT INTO ");
00434                 g_string_append_printf(fquery,
00435                                 "%s SET %s sitegroup=%d",
00436                                 table, 
00437                                 sql,
00438                                 object_sitegroup);
00439                 gchar *tmpstr = g_string_free(fquery, FALSE);
00440                 
00441                 qr = mysql_query(object->mgd->msql->mysql, tmpstr);
00442                 g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "query=%s", tmpstr);
00443                 
00444                 if (qr != 0) {
00445                         g_warning("query failed: %s \n %s", 
00446                                         tmpstr, 
00447                                         mysql_error(object->mgd->msql->mysql));
00448                 } else {
00449                         /* Keep backward compatibility ( repligard's table )*/
00450                         /* No need to define typename here. It's only type's
00451                          * "external" data */
00452                         if ((query->use_lang == 1) && (qr == 0)) {
00453                                 rid = mysql_insert_id(object->mgd->msql->mysql);
00454                                 gchar *guid = midgard_guid_new(object->mgd);
00455                                 fquery =  g_string_new("INSERT INTO repligard ");
00456                                 g_string_append_printf(fquery,
00457                                                 "(realm,guid,id,changed,action,sitegroup)"
00458                                                 " VALUES ('%s', '%s', %d , NULL, 'create', %d)", 
00459                                                 table, guid, rid, object_sitegroup);
00460                                 gchar *rtmpstr = g_string_free(fquery, FALSE);
00461                                 g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "query=%s", rtmpstr);
00462                                 qr = mysql_query(object->mgd->msql->mysql, rtmpstr);
00463                                 if (qr != 0) 
00464                                         g_warning("query failed: %s \n %s",
00465                                                         rtmpstr,
00466                                                         mysql_error(object->mgd->msql->mysql));
00467                                 g_free(guid);
00468                                 g_free(rtmpstr);
00469                         }
00470                 }               
00471                 g_free(tmpstr);
00472         }
00473 }
00474 
00475 void _update_records(gpointer key, gpointer value, gpointer userdata)
00476 {
00477         gchar *table = (gchar *) key;
00478         gchar *sql = (gchar *) value, *tmpstr = NULL;
00479         const gchar *otable;
00480         MgdSchemaTypeQuery *query;
00481         gint qr, doins = 0;
00482         gpointer rid;
00483         GString *where;
00484         MgdObject *object = (MgdObject *) userdata;
00485         guint object_sitegroup, id;
00486 
00487         g_object_get(G_OBJECT(object), "sitegroup", 
00488                         &object_sitegroup, NULL);       
00489         g_object_get(G_OBJECT(object), "id",
00490                         &id, NULL);
00491         
00492         otable = midgard_object_class_get_table(
00493                         MIDGARD_OBJECT_GET_CLASS(object));
00494         
00495         if(!g_str_equal(otable, table)){
00496                         
00497                 query = g_hash_table_lookup(object->data->tables, table); 
00498                 if(!query)
00499                         return;
00500                 
00501                 if (query->use_lang) {
00502                         where = g_string_new(" sid=");
00503                         g_string_append_printf(where,
00504                                         "%d AND lang=%d",
00505                                         id, mgd_lang(object->mgd));
00506                         tmpstr = g_string_free(where, FALSE);
00507                         rid =  midgard_query_field_get(object->mgd,
00508                                         "id", 
00509                                         table, 
00510                                         (const gchar*)tmpstr);
00511                         g_free(tmpstr);
00512                         
00513                         if(rid != NULL) {
00514                                 id = (guint) atoi(rid);
00515                                 where = g_string_new("UPDATE ");
00516                                 g_string_append_printf(where, 
00517                                                 "%s SET %s sitegroup=%d "
00518                                                 "WHERE id=%d AND sitegroup=%d",
00519                                                 table, sql, object_sitegroup,
00520                                                 id, object_sitegroup);
00521                         } else {
00522                                 where = g_string_new("INSERT INTO ");
00523                                 g_string_append_printf(where, 
00524                                                 "%s SET %s sitegroup=%d",
00525                                                 table, sql,
00526                                                 object_sitegroup);
00527                                 doins = 1;
00528                         }
00529                 } else {
00530                         /* TODO Add "join" fields */
00531                         where = g_string_new("UPDATE ");
00532                         g_string_append_printf(where,
00533                                         "%s SET %s, sitegroup=%d",
00534                                         table, sql, object_sitegroup);
00535                 }
00536 
00537                 tmpstr = g_string_free(where, FALSE);
00538                 qr = mysql_query(object->mgd->msql->mysql, tmpstr);
00539                                                 
00540                 if (query->use_lang && qr == 1 && doins == 1) {
00541                         rid =  midgard_query_field_get(object->mgd,
00542                                         "id",
00543                                         table,
00544                                         tmpstr);
00545                         if(rid != NULL) 
00546                                 id = (guint) atoi(rid);
00547                 }
00548                 g_free(tmpstr);
00549                 if (qr) {
00550                         /* Keep backward compatibility ( repligard's table )*/
00551                         if (query->use_lang == 1)
00552                                 UPDATE_REPLIGARD(object->mgd, table, id);  
00553                 }
00554         }                                                                                       
00555 }
00556 
00557 /* TODO, replace execute with distinct if needed */  
00558 gboolean _object_in_tree(MgdObject *object)
00559 {
00560         guint n_objects = 0;
00561         GParamSpec *name_prop, *up_prop, *primary;
00562         GValue pval = {0,}, fval = {0,};
00563 
00564         MidgardObjectClass *klass = MIDGARD_OBJECT_GET_CLASS(object);
00565         const gchar *primary_prop = midgard_object_class_get_primary_property(klass);
00566         const gchar *upname = midgard_object_class_get_parent_property(klass);
00567         if(upname == NULL)
00568                 upname = midgard_object_class_get_up_property(klass);
00569 
00570         if(upname == NULL)
00571                 return FALSE;
00572         
00573         up_prop = g_object_class_find_property(
00574                         G_OBJECT_GET_CLASS(G_OBJECT(object)), upname);
00575         name_prop = g_object_class_find_property(
00576                         G_OBJECT_GET_CLASS(G_OBJECT(object)), "name");
00577 
00578         if((name_prop == NULL) || (up_prop == NULL))
00579                 return FALSE;
00580         
00581         MidgardQueryBuilder *builder =
00582                 midgard_query_builder_new(object->mgd,
00583                                 G_OBJECT_TYPE_NAME(object));
00584         /* Add up or parent constraint */
00585         g_value_init(&pval,up_prop->value_type);
00586         g_object_get_property(G_OBJECT(object), upname, &pval);
00587         midgard_query_builder_add_constraint(builder,
00588                         upname,
00589                         "=", &pval);
00590         g_value_unset(&pval);
00591                         
00592         /* Add name property constraint */
00593         g_value_init(&pval,name_prop->value_type);
00594         g_object_get_property(G_OBJECT(object), "name", &pval);
00595         /* Check empty name, not null */
00596         const gchar *tmpstr = g_value_get_string(&pval);
00597         if(!tmpstr)
00598                 tmpstr = "";
00599         if(g_str_equal(tmpstr, "")){
00600                 g_object_unref(builder);
00601                 g_value_unset(&pval);
00602                 return FALSE;
00603         }
00604         midgard_query_builder_add_constraint(builder,
00605                         "name",
00606                         "=", &pval);
00607         g_value_unset(&pval);
00608                                  
00609         GObject **ret_object = 
00610                 midgard_query_builder_execute(
00611                                 builder, &n_objects);
00612 
00613         /* Name is not duplicated, return */
00614         if(n_objects < 1){
00615                 g_object_unref(G_OBJECT(builder));
00616                 return FALSE;
00617         }
00618                         
00619         /* we must compare primary properties and its values.
00620          * if eqaul , we may update object , if not we return false */
00621         primary = g_object_class_find_property(
00622                         G_OBJECT_GET_CLASS(G_OBJECT(ret_object[0])), primary_prop);
00623         
00624         gboolean duplicate = TRUE;
00625         g_value_init(&fval, primary->value_type);
00626         g_object_get_property(G_OBJECT(ret_object[0]), primary_prop, &fval);
00627         
00628         g_value_init(&pval, primary->value_type);
00629         g_object_get_property(G_OBJECT(object), primary_prop, &pval);
00630                 
00631         switch(primary->value_type){
00632 
00633                 case G_TYPE_UINT:
00634                         if(g_value_get_uint(&fval) == g_value_get_uint(&pval))
00635                                 duplicate = FALSE;
00636                         break;
00637 
00638                 case G_TYPE_STRING:
00639                         if(g_str_equal(g_value_get_string(&fval),
00640                                                 g_value_get_string(&pval)))
00641                                 duplicate = FALSE;
00642                         break;                                  
00643         }
00644 
00645         g_object_unref(ret_object[0]);
00646         g_object_unref(builder);
00647                 
00648         if(duplicate)
00649                 return TRUE;
00650         
00651         /* PP:I am not sure if we really need this for every object. 
00652          * Static path for dynamic applications is needless.
00653          * However path should be build or used for applications 
00654          * which do not change paths for libraries snippets code
00655          * */
00656         /* (void *) midgard_object_build_path(mobj); */
00657   
00658         return FALSE;
00659 }
00660 
00661 gboolean _midgard_object_update(MgdObject *gobj, 
00662                 _ObjectActionUpdate replicate)
00663 {
00664         g_assert(gobj != NULL);
00665         g_assert(gobj->mgd != NULL);
00666         
00667         gchar *sqlsetf = "", *fquery = "";
00668         guint  qr, oid, id = 0;
00669         GHashTable *sqls;
00670         const gchar *table;
00671         guint object_sitegroup , current_sitegroup;
00672 
00673         if(!_midgard_core_object_is_valid(gobj))
00674                 return FALSE;
00675 
00676         MIDGARD_ERRNO_SET(gobj->mgd, MGD_ERR_OK);
00677 
00678         /* Disable person check */
00679         /*
00680         if(gobj->mgd->person == NULL) {
00681                 MIDGARD_ERRNO_SET(gobj->mgd, MGD_ERR_ACCESS_DENIED);
00682                 return FALSE;
00683         }
00684         */
00685         
00686         if (gobj->data == NULL) {
00687                 MIDGARD_ERRNO_SET(gobj->mgd, MGD_ERR_INTERNAL);
00688                 return FALSE;
00689         }
00690         table = midgard_object_class_get_table(MIDGARD_OBJECT_GET_CLASS(gobj));
00691     
00692         if(table  == NULL) {
00693                 /* Object has no storage defined. Return FALSE as there is nothing to update */
00694                 g_warning("Object '%s' has no table defined!", gobj->cname);
00695                 MIDGARD_ERRNO_SET(gobj->mgd, MGD_ERR_INTERNAL);
00696                 return FALSE;
00697         }
00698 
00699         current_sitegroup = mgd_sitegroup(gobj->mgd);
00700         g_object_get(G_OBJECT(gobj), "sitegroup", &object_sitegroup, NULL);
00701 
00702         /* FIXME: this can not be checked like this. It can be checked 
00703          * SG borders are "crossed" only if bindings objects are 1:1 with core's 
00704          * ones. */
00705         /*if((mgd_isroot(gobj->mgd)) && (object_sitegroup > 0)){
00706                 g_critical("Sitegroup violation! Can not redefine object's sitegroup");
00707                 MIDGARD_ERRNO_SET(gobj->mgd, MGD_ERR_SITEGROUP_VIOLATION);
00708                 return FALSE;
00709         }       
00710         */
00711         /* Just in case. This should be done in _object_set_property, 
00712          * but we do not provide objects' 1:1 mapping for midgard-php4.
00713          * SG0 Midgard Administrator is still able to change sitegroup */
00714         if((current_sitegroup > 0) && (object_sitegroup > 0) &&
00715                         (current_sitegroup != object_sitegroup))
00716                 g_object_set(G_OBJECT(gobj), "sitegroup", 
00717                                 mgd_sitegroup(gobj->mgd) , NULL);
00718 
00719         /* Check duplicates and parent field */
00720         if(_object_in_tree(gobj)) {             
00721                 MIDGARD_ERRNO_SET(gobj->mgd, MGD_ERR_DUPLICATE);
00722                 return FALSE;
00723         }
00724         /* we need id to set multilanged object's sid property 
00725          * * * and for repligard table */
00726         g_object_get((GObject *) gobj, "id", &oid , NULL);
00727         
00728         /* Set sid and lang property */    
00729         if (gobj->data->use_lang) {
00730                 g_object_set((GObject *) gobj, "sid", oid , NULL);
00731                 g_object_set((GObject *) gobj, "lang", mgd_lang(gobj->mgd), NULL);
00732         }
00733         
00734         sqls = _build_create_or_update_query(gobj);
00735         sqlsetf = g_hash_table_lookup(sqls, gobj->data->table);
00736 
00737         GString *sql = g_string_new("UPDATE ");
00738         g_string_append_printf(sql, 
00739                         "%s SET %s ",
00740                         table, sqlsetf);
00741         
00742         /* METADATA START */
00743         gchar *person_guid ;
00744         MgdObject *person = (MgdObject *)gobj->mgd->person;                     
00745         if(person){
00746                 if(G_IS_OBJECT(G_OBJECT(person)))
00747                         g_object_get(G_OBJECT(person), "guid", &person_guid, NULL);
00748         }else {
00749                 /* g_info("Anonymous mode"); */
00750                 person_guid = g_strdup("");
00751         }
00752                 
00753         GValue tval = {0, };
00754         g_value_init(&tval, midgard_timestamp_get_type());
00755         midgard_timestamp_set_time(&tval, time(NULL));
00756         gchar *timeupdated = midgard_timestamp_dup_string(&tval);
00757 
00758         /* If object is imported it's revised time should be 
00759          * untouched as property value is copied from imported 
00760          * object */
00761         gchar *revised_time;
00762         gint revision_count = gobj->metadata->private->revision;
00763         
00764         if(replicate == OBJECT_UPDATE_IMPORTED){
00765                 revised_time = gobj->metadata->private->revised;
00766         } else {
00767                 revised_time = timeupdated;
00768                 revision_count++;
00769         }
00770         
00771         switch(replicate){
00772 
00773                 case OBJECT_UPDATE_NONE:
00774                         
00775                         /* FIXME , revision property is set in hope it will be ok 
00776                          * I see no other way to set correct revision number without additional 
00777                          * SELECT made only to get real revision value */
00778                         /* TODO , move it to private structure when php4 module binding
00779                          * will use 1:1 objects mapping */
00780                         g_string_append_printf(sql,
00781                                         "metadata_revisor='%s', metadata_revised='%s',"
00782                                         "metadata_revision=%d ",
00783                                         person_guid, revised_time, revision_count);
00784                         
00785                         gchar *metasql = midgard_metadata_get_sql(gobj->metadata);
00786                         g_string_append_printf(sql, " %s ", metasql);
00787                         g_free(metasql);
00788                         
00789                         g_object_set(G_OBJECT(gobj->metadata),
00790                                         "revisor", person_guid,
00791                                         "revised", timeupdated,
00792                                         "revision", revision_count,
00793                                         NULL);
00794                         
00795                         g_free(person_guid);
00796                         g_free(timeupdated);
00797                         break;
00798                 
00799                 case OBJECT_UPDATE_EXPORTED:
00800                         g_string_append_printf(sql,
00801                                         "metadata_exported='%s'",
00802                                         timeupdated);
00803                         g_free(gobj->private->exported);
00804                         gobj->private->exported = g_strdup(timeupdated);
00805                         g_object_set(G_OBJECT(gobj->metadata),
00806                                         "exported", timeupdated, 
00807                                         NULL);
00808                         break;
00809 
00810                 case OBJECT_UPDATE_IMPORTED:
00811                         g_string_append_printf(sql,
00812                                         "metadata_imported='%s'"
00813                                         ",metadata_exported='%s'"
00814                                         ",metadata_revisor='%s' "
00815                                         ",metadata_revised='%s' "
00816                                         ",metadata_revision=%d  "
00817                                         ",metadata_creator='%s' ",
00818                                         timeupdated, 
00819                                         gobj->metadata->private->exported,
00820                                         gobj->metadata->private->revisor,
00821                                         revised_time,
00822                                         revision_count,
00823                                         gobj->metadata->private->creator);
00824                         
00825                         g_free(gobj->private->imported);
00826                         gobj->private->imported = g_strdup(timeupdated);
00827                         /*g_object_set(G_OBJECT(gobj->metadata),
00828                                         "exported", exported_time,
00829                                         "imported", timeupdated,
00830                                         NULL);
00831                         */              
00832                         break;
00833         }
00834 
00835         /* METADATA END */
00836 
00837         /* get object's primary property to create WHERE part */
00838         GValue pval = {0, };
00839         const gchar *pprop = midgard_object_class_get_primary_property(
00840                         MIDGARD_OBJECT_GET_CLASS(gobj));
00841         
00842         GParamSpec *propval =  g_object_class_find_property(
00843                         G_OBJECT_GET_CLASS(G_OBJECT(gobj)), pprop);
00844         
00845         g_value_init(&pval, propval->value_type);
00846         switch(propval->value_type){
00847                 
00848                 case G_TYPE_STRING:
00849                         /* id need for repligard anyway */
00850                         g_object_get(G_OBJECT(gobj), "id", &id, NULL);
00851                         if(gobj->private->guid == NULL)
00852                                 g_critical("Object's guid is NULL. Can not update");
00853                         g_string_append_printf(sql,
00854                                         " WHERE %s = '%s'", pprop, gobj->private->guid);
00855                         break;
00856                 
00857                 case G_TYPE_UINT:
00858                         g_object_get_property(G_OBJECT(gobj), pprop, &pval);
00859                         g_string_append_printf(sql,
00860                                         " WHERE %s = %d", pprop, g_value_get_uint(&pval));
00861                         id = g_value_get_uint(&pval);
00862                         if(id == 0)
00863                                 g_warning("Object's ID is 0. Can not update");
00864                         break;
00865         }
00866         g_value_unset(&pval);
00867 
00868         /* Add sitegroup, if user is non root */ 
00869         if(!mgd_isroot(gobj->mgd)){
00870                 g_string_append_printf(sql,
00871                                 " AND %s.sitegroup = %d",
00872                                 table,
00873                                 object_sitegroup);
00874         }                                         
00875         
00876         guint object_size;
00877         g_object_get(G_OBJECT(gobj->metadata), "size", &object_size, NULL);
00878         fquery = g_string_free(sql, FALSE);
00879         if(midgard_quota_size_is_reached(gobj, object_size)){
00880                 MIDGARD_ERRNO_SET(gobj->mgd, MGD_ERR_QUOTA);
00881                 g_free(fquery);
00882                 return FALSE;
00883         }
00884     
00885         /* Execute update query */
00886         g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "query=%s", fquery);
00887         qr = mysql_query(gobj->mgd->msql->mysql, fquery);
00888         g_free(fquery);
00889         
00890         if (qr != 0) {
00891                 g_warning("query failed: %s", 
00892                                 mysql_error(gobj->mgd->msql->mysql));
00893                 MIDGARD_ERRNO_SET(gobj->mgd, MGD_ERR_INTERNAL);
00894                 return FALSE;
00895         } else {
00896                 midgard_quota_update(gobj);   
00897                 /* Update repligard's table 
00898                  * I need to use id in repligard table, do not update repligard table
00899                  * when object has no integer primary property */
00900                 
00901                 if(id > 0){             
00902                         sql = g_string_new("UPDATE repligard SET changed=NULL,action='update',");
00903                         g_string_append_printf(sql,
00904                                         "typename='%s' WHERE guid='%s' AND realm='%s'",
00905                                         G_OBJECT_TYPE_NAME(gobj),
00906                                         gobj->private->guid,
00907                                         table);
00908                         fquery = g_string_free(sql, FALSE);
00909                         g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "query=%s", fquery);
00910                         mysql_query(gobj->mgd->msql->mysql, fquery);
00911                         g_free(fquery);
00912                         /* Should I worry about error in repligard table here? */
00913                 }
00914         }
00915 
00916         /* sqls = _build_create_or_update_query(gobj); */
00917         g_hash_table_foreach(sqls, _update_records, gobj);
00918         g_hash_table_destroy(sqls);   
00919         MIDGARD_ERRNO_SET(gobj->mgd, MGD_ERR_OK);
00920         
00921         return TRUE;
00922 }
00923 
00924 gboolean midgard_object_update(MgdObject *self)
00925 {
00926         return _midgard_object_update(self, OBJECT_UPDATE_NONE);
00927 }
00928 
00929 
00930 /* Create object's data in storage */
00931 gboolean _midgard_object_create(MgdObject *object, const gchar *create_guid)
00932 {
00933         gchar *sqlsetf = "", *fquery;
00934         guint  qr, rid, object_sitegroup;
00935         GHashTable *sqls;
00936         GString *query;
00937         const gchar *table;
00938         
00939         if (object->data == NULL)
00940                 return FALSE;
00941 
00942         if(!_midgard_core_object_is_valid(object))
00943                 return FALSE;
00944         MIDGARD_ERRNO_SET(object->mgd, MGD_ERR_OK);     
00945 
00946         /* Disable person check */
00947         /*
00948         if(object->mgd->person == NULL) {
00949                 MIDGARD_ERRNO_SET(object->mgd, MGD_ERR_ACCESS_DENIED);
00950                 return FALSE;
00951         }
00952         */
00953         
00954         if((table = midgard_object_class_get_table(MIDGARD_OBJECT_GET_CLASS(object))) == NULL) {
00955                 /* Object has no storage defined. Return FALSE as there is nothing to create */
00956                 g_warning("Object '%s' has no table or storage defined!",
00957                                 object->cname);    
00958                 MIDGARD_ERRNO_SET(object->mgd, MGD_ERR_NOT_EXISTS);    
00959                 return FALSE;  
00960         }
00961         
00962         /* Set object's sitegroup */
00963         if(!mgd_isroot(object->mgd)) {
00964                 g_object_set(G_OBJECT(object), "sitegroup",
00965                                 midgard_sitegroup_get_id(object->mgd) , NULL);
00966         } 
00967         /* Get object_sitegroup, this value will change depending on 
00968          * who is currently logged in */
00969         g_object_get(G_OBJECT(object), "sitegroup", &object_sitegroup, NULL);
00970         
00971         /* If Object has upfield set , check if property which points to up is set and has some value. 
00972          * In other case, create Object and do INSERT, 
00973          * as object is not "treeable" and may be created without 
00974          * any parent object(typical for parameters or attachments).
00975          */ 
00976         if(_object_in_tree(object)) {
00977                 MIDGARD_ERRNO_SET(object->mgd, MGD_ERR_DUPLICATE);
00978                 return FALSE;
00979         }
00980 
00981         /* Create object's guid */
00982         gchar *guid;
00983         if(create_guid == NULL)
00984                 guid = midgard_guid_new(object->mgd);
00985         else
00986                 guid = g_strdup(create_guid);
00987 
00988         g_object_set(G_OBJECT(object), "guid", guid , NULL);
00989         
00990         sqls = _build_create_or_update_query(object);
00991         sqlsetf = g_hash_table_lookup(sqls, object->data->table);
00992 
00993         /* Create object record in its table */
00994         query = g_string_new("INSERT INTO ");
00995         g_string_append_printf(query,
00996                         "%s SET %s guid='%s',",
00997                         table, sqlsetf, guid);
00998         
00999         /* Set sitegroup from current sitegroup only when logged in person is not SG0 admin */
01000         if(!mgd_isroot(object->mgd))
01001                 object_sitegroup = midgard_sitegroup_get_id(object->mgd);
01002         
01003         g_string_append_printf(query,
01004                         "sitegroup=%d,", object_sitegroup);
01005         
01006         g_hash_table_destroy(sqls); 
01007         
01008         /* Set metadata */
01009         /*g_signal_emit_by_name(object->metadata,
01010          * "set_created", NULL); */
01011         gchar *person_guid ;
01012         MgdObject *person = (MgdObject *)object->mgd->person;
01013         if(person){
01014                 if(G_IS_OBJECT(G_OBJECT(person)))
01015                         g_object_get(G_OBJECT(person), "guid", &person_guid, NULL);
01016         } else {
01017                 /* g_info("Anonymous mode"); */
01018                 person_guid = g_strdup("");
01019         }
01020         
01021         /* Set metadata fields creator and created values*/
01022         GValue tval = {0, };    
01023         time_t utctime = time(NULL);
01024         g_value_init(&tval, MIDGARD_TYPE_TIMESTAMP);    
01025         midgard_timestamp_set_time(&tval, utctime);
01026         gchar *timecreated = midgard_timestamp_dup_string(&tval);
01027         g_value_unset(&tval);   
01028         guint object_size;
01029         g_object_get(G_OBJECT(object->metadata), "size", &object_size, NULL);
01030         g_string_append_printf(query,   
01031                         "metadata_creator='%s', metadata_created='%s', "
01032                         "metadata_revised='%s', metadata_revision=0, "
01033                         "metadata_revisor='%s', metadata_size=%d ",      
01034                         person_guid, timecreated,
01035                         timecreated, person_guid,
01036                         object_size);
01037         
01038         /* Set metadata properties */
01039         g_object_set(G_OBJECT(object->metadata), 
01040                         "creator", person_guid, 
01041                         "created", timecreated,                 
01042                         "revised", timecreated,
01043                         "revision", 0,
01044                         "revisor", person_guid,
01045                         "published", timecreated,
01046                         NULL);    
01047         
01048         gchar *metasql = midgard_metadata_get_sql(object->metadata); 
01049         g_string_append_printf(query, " %s ", metasql);
01050         
01051         g_free(metasql);
01052         g_free(timecreated);
01053         g_free(person_guid);
01054         /* metadata end */
01055         
01056         fquery = g_string_free(query, FALSE);
01057         
01058         if(!midgard_quota_create(object)){
01059                 g_free(fquery);
01060                 return FALSE;
01061         }
01062         g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "query=%s", fquery);
01063         
01064         qr = mysql_query(object->mgd->msql->mysql, fquery);
01065         g_free(fquery);
01066         
01067         if (qr != 0) {
01068                 g_warning("\n\n QUERY FAILED: %s \n\n", mysql_error(object->mgd->msql->mysql));
01069                 g_free(guid);
01070                 g_object_set(G_OBJECT(object), "guid", "" , NULL);
01071                 MIDGARD_ERRNO_SET(object->mgd, MGD_ERR_NOT_EXISTS);
01072                 return FALSE;
01073         } else {
01074                 /* Create repligard and other tables entries */
01075                 if ((rid = mysql_insert_id(object->mgd->msql->mysql))){
01076                         g_object_set(G_OBJECT(object), "id", rid, NULL); /* FIXME */            
01077                         midgard_quota_update(object);           
01078                         query = g_string_new("INSERT INTO repligard SET ");
01079                         g_string_append_printf(query, 
01080                                         "realm='%s', guid='%s', changed=NULL, "
01081                                         "action='create', typename='%s', id=%d, "
01082                                         " sitegroup=%d, object_action = %d ",
01083                                         table, guid, object->cname, rid, 
01084                                         object_sitegroup,
01085                                         MGD_OBJECT_ACTION_NONE);
01086                         
01087                         g_free(guid);           
01088                         fquery = g_string_free(query, FALSE);
01089                         g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "query=%s", fquery);
01090                         qr = mysql_query(object->mgd->msql->mysql, fquery);
01091                         g_free(fquery);
01092                         
01093                         if (qr != 0) {
01094                                 g_warning("query failed: %s", mysql_error(object->mgd->msql->mysql));
01095                                 MIDGARD_ERRNO_SET(object->mgd, MGD_ERR_INTERNAL);                
01096                         }
01097                         
01098                         /* Set sid property to newly created object's id if object has such property */
01099                         if (g_object_class_find_property(
01100                                                 G_OBJECT_GET_CLASS(G_OBJECT(object)), "sid") != NULL) 
01101                                 g_object_set(G_OBJECT(object), "sid", rid, NULL);
01102                         /* Set lang property */
01103                         if (g_object_class_find_property(
01104                                                 G_OBJECT_GET_CLASS(G_OBJECT(object)), "lang") != NULL)
01105                                 g_object_set(G_OBJECT(object), 
01106                                                 "lang", midgard_lang_get(object->mgd), NULL);
01107                         
01108                         sqls = _build_create_or_update_query(object);
01109                         g_hash_table_foreach(sqls, _insert_records, object);
01110                         
01111                         g_hash_table_destroy(sqls);             
01112                         g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG,"Object %s created with id=%d", 
01113                                         object->cname, rid);
01114                         return TRUE;
01115                 }
01116         }
01117         MIDGARD_ERRNO_SET(object->mgd, MGD_ERR_INTERNAL);
01118         return FALSE;   
01119 }
01120 
01121 gboolean midgard_object_create(MgdObject *object)
01122 {
01123         return _midgard_object_create(object, NULL);
01124 }
01125 
01126 
01127 
01128 void _object_copy_properties(GObject *src, GObject *dest)
01129 {
01130         g_assert(src != NULL && dest != NULL);
01131 
01132         guint nprop, i;
01133         GValue pval = {0, };
01134         GValue doval = {0, };
01135         GParamSpec **props = g_object_class_list_properties(
01136                         G_OBJECT_GET_CLASS(src),
01137                         &nprop);
01138         
01139         for(i = 0; i <+ nprop; i++){            
01140                 
01141                 g_value_init(&pval, props[i]->value_type);      
01142 
01143                 if(props[i]->value_type == G_TYPE_OBJECT){                      
01144                 
01145                         g_object_get_property(src,
01146                                         props[i]->name,
01147                                         &pval);
01148                         
01149                         g_value_init(&doval, props[i]->value_type);
01150                         g_object_get_property(dest,
01151                                         props[i]->name,
01152                                         &doval);
01153 
01154                         _object_copy_properties(
01155                                         G_OBJECT(g_value_get_object(&pval)),
01156                                         G_OBJECT(g_value_get_object(&doval))
01157                                         );
01158                         g_value_unset(&doval);
01159 
01160                 } else {
01161 
01162                         g_object_get_property(G_OBJECT(src),
01163                                         props[i]->name,
01164                                         &pval);
01165                         g_object_set_property(G_OBJECT(dest),
01166                                         props[i]->name,
01167                                         &pval);
01168                 }
01169 
01170                 g_value_unset(&pval);
01171         }
01172 
01173         g_free(props);
01174 }
01175 
01176 
01177 /* Get object by its id property, id must be uint type */
01178 gboolean  midgard_object_get_by_id(MgdObject *object)
01179 {
01180         g_assert(object != NULL);
01181         g_assert(object->mgd != NULL);
01182 
01183         /* Reset errno */
01184         MIDGARD_ERRNO_SET(object->mgd, MGD_ERR_OK);
01185         
01186         guint n_objects = 0;
01187         GParamSpec *prop;
01188         MidgardObjectClass *klass = MIDGARD_OBJECT_GET_CLASS(object);
01189         
01190         /* Find "primary" property , just in case of fatal error */
01191         prop = g_object_class_find_property(
01192                         (GObjectClass*)klass,
01193                         "id");
01194         if(prop == NULL){
01195                 MIDGARD_ERRNO_SET(object->mgd, MGD_ERR_INTERNAL);
01196                 g_warning("Primary property id not found for object's klass '%s'",
01197                                 G_OBJECT_TYPE_NAME(object));
01198                 return FALSE;
01199         }
01200 
01201         /* Stop when property is not uint type */
01202         g_assert((prop->value_type == G_TYPE_UINT));
01203         
01204         /* Initialize QB */
01205         MidgardQueryBuilder *builder =
01206                 midgard_query_builder_new(object->mgd, 
01207                                 G_OBJECT_TYPE_NAME(object));
01208         
01209         if(!builder) {
01210                 MIDGARD_ERRNO_SET(object->mgd, MGD_ERR_INTERNAL);
01211                 g_warning("Invalid query builder configuration (%s)",
01212                                 G_OBJECT_TYPE_NAME(object));
01213                 return FALSE;
01214         }
01215 
01216         /* Get primary's property value */
01217         GValue pval = {0,};
01218         g_value_init(&pval,prop->value_type);   
01219         g_object_get_property(G_OBJECT(object), "id", &pval);
01220         if (midgard_query_builder_add_constraint(builder,
01221                                 "id",
01222                                 "=", &pval)) {
01223                 
01224                 GObject **ret_object = midgard_query_builder_execute(
01225                                 builder, &n_objects);
01226 
01227                 g_value_unset(&pval);   
01228                 g_object_unref(G_OBJECT(builder));
01229                                 
01230                 if(n_objects < 1) {
01231                         MIDGARD_ERRNO_SET(object->mgd, MGD_ERR_NOT_EXISTS);
01232                         return FALSE;
01233                 }
01234         
01235                 _object_copy_properties(ret_object[0],
01236                                 G_OBJECT(object));
01237 
01238                 g_object_unref(ret_object[0]);
01239                 g_free(ret_object);
01240 
01241                 MIDGARD_ERRNO_SET(object->mgd, MGD_ERR_OK);
01242                 return TRUE;
01243         }
01244         return FALSE;
01245 }
01246 
01247 GObject **midgard_object_find(MgdObject *object, guint *n_objects)
01248 {
01249         GParamSpec **props;
01250         guint propn, i;
01251         GValue pval = {0,};
01252         
01253         MIDGARD_ERRNO_SET(object->mgd, MGD_ERR_OK);
01254 
01255         props = g_object_class_list_properties(
01256                         G_OBJECT_CLASS(MIDGARD_OBJECT_GET_CLASS(object)), &propn);
01257         if(!props){
01258                 g_warning("No properties found for %s class!",
01259                                 object->cname);
01260                 MIDGARD_ERRNO_SET(object->mgd, MGD_ERR_INTERNAL);
01261                 return NULL;
01262         }
01263         
01264         MidgardQueryBuilder *builder =
01265                         midgard_query_builder_new(object->mgd, object->cname);
01266         if(!builder){
01267                 MIDGARD_ERRNO_SET(object->mgd, MGD_ERR_INTERNAL);
01268                 return NULL;
01269         }
01270 
01271         for(i = 0; i < propn; i++) {
01272                 g_value_init(&pval,props[i]->value_type);
01273                 g_object_get_property(G_OBJECT(object),                                                                             props[i]->name, &pval);
01274                 switch (props[i]->value_type) {
01275                         
01276                         case G_TYPE_STRING:
01277                                 if(g_value_get_string(&pval))
01278                                         midgard_query_builder_add_constraint(builder,
01279                                                         props[i]->name, "=", &pval);
01280                                 break;
01281 
01282                         case G_TYPE_UINT:
01283                                 if(g_value_get_uint(&pval))
01284                                         midgard_query_builder_add_constraint(builder,
01285                                                         props[i]->name, "=", &pval);
01286                                 break;
01287                         
01288                         case G_TYPE_INT:
01289                                 if(g_value_get_int(&pval))
01290                                         midgard_query_builder_add_constraint(builder,
01291                                                         props[i]->name, "=", &pval);
01292                                 break;
01293 
01294                         case G_TYPE_FLOAT:
01295                                 if(g_value_get_float(&pval))
01296                                         midgard_query_builder_add