00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00030 #include <config.h>
00031
00032 #include "midgard/midgard_legacy.h"
00033 #include "defaults.h"
00034 #if HAVE_CRYPT_H
00035 #include <crypt.h>
00036 #else
00037 #define _XOPEN_SOURCE
00038 #ifndef WIN32
00039 #include <unistd.h>
00040 #endif
00041 #endif
00042 #include <errno.h>
00043 #ifndef WIN32
00044 #include <unistd.h>
00045 #endif
00046
00047 #include "midgard/midgard_object.h"
00048 #include "schema.h"
00049
00051 const tree_node zero_node = {
00052 0,
00053 0,
00054 0,
00055 0,
00056 NULL,
00057 NULL
00058 };
00059
00061 #define ALLOC_TNODE(pool, node) {\
00062 (node) = (tree_node*)mgd_alloc(pool, sizeof(tree_node));\
00063 *(node) = zero_node;\
00064 }
00065
00082 static int walktree(midgard * mgd, tree_node * tree, int order, int level,
00083 int maxlevel, void *xparam, midgard_userfunc func)
00084 {
00085 int branch_ok = 1;
00086 tree_node *tmp;
00087 if(maxlevel && level > maxlevel) return 1;
00088 if (order && func)
00089 if(!(branch_ok = func(mgd, tree->id, level, xparam)))
00090 return 0;
00091 if(branch_ok > 0) {
00092 tmp = tree->child;
00093 while(tmp) {
00094 if(!walktree(mgd, tmp, order, level + 1, maxlevel, xparam, func))
00095 return 0;
00096 tmp = tmp->next;
00097 }
00098 }
00099 if ((!order) && func)
00100 if(!func(mgd, tree->id, level, xparam))
00101 return 0;
00102 return 1;
00103 }
00104
00123 int mgd_tree_get_level(midgard *mgd, midgard_pool * pool, const char *table,
00124 const char * upfield, const char * sort,
00125 int ** ids, tree_node ** nodes)
00126 {
00127 midgard_res *res;
00128 int i,n;
00129
00130 if(!ids) return 0;
00131 if(!upfield || !(*upfield)) upfield = "up";
00132 if((*ids)[0] && (*ids)[1]) {
00133 res = mgd_query(mgd,
00134 "SELECT id,$s FROM $s WHERE $s IN $D AND (sitegroup in (0, $d) OR $d<>0) ORDER BY $s,$s",
00135 upfield, table,
00136 upfield, *ids, mgd_sitegroup(mgd), mgd_isroot(mgd),
00137 upfield, sort ? sort : "id");
00138 } else {
00139 res = mgd_query(mgd,
00140 "SELECT id,$s FROM $s WHERE $s=$d AND (sitegroup in (0, $d) OR $d<>0) ORDER BY $s,$s",
00141 upfield, table,
00142 upfield, (*ids)[0], mgd_sitegroup(mgd), mgd_isroot(mgd),
00143 upfield, sort ? sort : "id");
00144 }
00145 if(!res || !(n = mgd_rows(res))) {
00146 nodes = NULL;
00147 ids = NULL;
00148 return 0;
00149 }
00150 *nodes = (tree_node *) mgd_alloc(pool, n * sizeof (tree_node));
00151 *ids = (int *) mgd_alloc(pool, (n + 1) * sizeof(int *));
00152 for(i = 0; mgd_fetch(res); i++) {
00153 (*ids)[i] = mgd_sql2int(res, 0);
00154 (*nodes)[i].id = (*ids)[i];
00155 (*nodes)[i].up = mgd_sql2int(res, 1);
00156 (*nodes)[i].level = 0;
00157 (*nodes)[i].size = 0;
00158 (*nodes)[i].child = NULL;
00159 (*nodes)[i].next = NULL;
00160
00161
00162 if(i && (*nodes)[i].up == (*nodes)[i-1].up) {
00163 (*nodes)[i-1].next = &((*nodes)[i]);
00164 }
00165 }
00166 (*ids)[i] = 0;
00167 mgd_release(res);
00168 return n;
00169 }
00170
00183 void mgd_tree_get_ids(tree_node * tree, int *ids, int *index) {
00184 tree_node * tmp;
00185
00186 if(!tree) return;
00187 ids[*index] = tree->id;
00188 (*index)++;
00189 tmp = tree->child;
00190 while(tmp) {
00191 mgd_tree_get_ids(tmp, ids, index);
00192 tmp = tmp->next;
00193 }
00194 }
00195
00203 int mgd_tree_init(tree_node * tree, int level) {
00204 tree_node * tmp;
00205
00206 if(!tree) return 0;
00207 tree->size = 1;
00208 tree->level = level;
00209 tmp = tree->child;
00210 while(tmp) {
00211 tree->size += mgd_tree_init(tmp, level + 1);
00212 tmp = tmp->next;
00213 }
00214
00215 return tree->size;
00216 }
00217
00230 tree_node * mgd_tree_build(midgard * mgd, midgard_pool * pool,
00231 const char * table, const char * upfield, int root,
00232 int maxlevel, const char * sort)
00233 {
00234 int root_ids[2] = {root, 0};
00235 int *child_ids = root_ids;
00236 tree_node *root_node, *parent_nodes, *child_nodes;
00237 int parent_num, child_num, i, j, k;
00238
00239 if(sort && (!strncmp(sort, "id", 2) || !strncmp(sort, "up", 2)
00240 || !strncmp(sort, "sitegroup", 9)))
00241 sort = NULL;
00242 ALLOC_TNODE(pool, root_node);
00243 root_node->id = root;
00244 parent_num = 1;
00245 parent_nodes = root_node;
00246 for(i = 0; !maxlevel || (i < maxlevel); i++) {
00247 child_num = mgd_tree_get_level(mgd, pool, table, upfield, sort,
00248 &child_ids, &child_nodes);
00249 if(!child_num) break;
00250
00251 if(parent_num > child_num) {
00252 for(j = 0; j < parent_num; j++) {
00253 for(k = 0; k < child_num; k++) {
00254
00255 if(parent_nodes[j].id != child_nodes[k].up) continue;
00256 parent_nodes[j].child = child_nodes + k;
00257 break;
00258 }
00259 }
00260 } else {
00261 for(k = 0; k < child_num; k++) {
00262 for(j = 0; j < parent_num; j++) {
00263
00264 if(parent_nodes[j].id != child_nodes[k].up) continue;
00265 parent_nodes[j].child = child_nodes + k;
00266
00267 while(child_nodes[k].next) k++;
00268 }
00269 }
00270 }
00271 parent_nodes = child_nodes;
00272 parent_num = child_num;
00273 }
00274 mgd_tree_init(root_node, 0);
00275 return root_node;
00276 }
00277
00295 MGD_API int mgd_walk_table_tree(midgard * mgd, const char *table, const char *upfield,
00296 int root, int maxlevel, int order, void *xparam,
00297 midgard_userfunc func, const char * sort)
00298 {
00299 midgard_pool *pool;
00300 tree_node *tree;
00301 int ret;
00302
00303 pool = mgd_alloc_pool();
00304
00305 tree = mgd_tree_build(mgd, pool, table, upfield, root, maxlevel, sort);
00306
00307 if (!tree) {
00308 return 0;
00309 }
00310
00311 ret = walktree(mgd, tree, order, 0, maxlevel, xparam, func);
00312 mgd_free_pool(pool);
00313 return ret;
00314 }
00315
00328 MGD_API int *mgd_tree(midgard * mgd, const char *table, const char *upfield,
00329 int id, int maxlevel, const char *sort)
00330 {
00331 int *ids, i = 0;
00332 tree_node * tree;
00333 midgard_pool * pool;
00334
00335 pool = mgd_alloc_pool();
00336 tree = mgd_tree_build(mgd, pool, table, upfield, id, maxlevel, sort);
00337 if(!tree) return NULL;
00338
00339 ids = (int *)malloc((tree->size + 1) * sizeof(int));
00340
00341 mgd_tree_get_ids(tree, ids, &i);
00342 ids[i] = 0;
00343
00344 mgd_free_pool(pool);
00345 return ids;
00346 }
00347
00358 MGD_API int mgd_is_in_tree(midgard * mgd, const char * table,
00359 const char * upfield, int root, int id)
00360 {
00361 midgard_res * res;
00362 midgard_pool * pool;
00363 int level=0;
00364
00365 pool = mgd_alloc_pool();
00366
00367 if(!table) return 0;
00368 if(!upfield || !(*upfield)) upfield = "up";
00369 while(root != id) {
00370 res = mgd_query(mgd,
00371 "SELECT $s FROM $s WHERE id=$d AND (sitegroup in (0, $d) OR $d<>0)",
00372 upfield, table, id, mgd_sitegroup(mgd), mgd_isroot(mgd));
00373 if(!res || !mgd_rows(res)) {
00374 mgd_free_pool(pool);
00375 return 0;
00376 }
00377 mgd_fetch(res);
00378 id = mgd_sql2int(res, 0);
00379 level++;
00380 mgd_release(res);
00381 }
00382 mgd_free_pool(pool);
00383 if(root == id) return level+1;
00384 return 0;
00385 }
00386
00387
00388 MGD_API gchar *midgard_object_build_path(MgdObject *mobj)
00389 {
00390 g_assert(mobj != NULL);
00391 midgard_res * res;
00392 midgard_pool * pool;
00393 gchar *path = NULL, *pename;
00394 gint id;
00395 const gchar *parent_table, *upfield;
00396
00397 pool = mgd_alloc_pool();
00398 if (!pool)
00399 return NULL;
00400
00401 MgdObject *parent = midgard_object_new(mobj->mgd,
00402 midgard_object_parent(mobj), NULL);
00403
00404 MidgardObjectClass *parent_class = MIDGARD_OBJECT_GET_CLASS(parent);
00405 MidgardObjectClass *klass = MIDGARD_OBJECT_GET_CLASS(mobj);
00406
00407 parent_table = midgard_object_class_get_table(parent_class);
00408 upfield = parent_class->data->query->upfield;
00409
00410 g_object_unref(parent);
00411
00412 if ((parent_table == NULL) || (upfield == NULL))
00413 return NULL;
00414
00415 g_log("midgard-lib", G_LOG_LEVEL_DEBUG, "Walk the tree using table '%s' and upfield: '%s'", parent_table, upfield);
00416
00417 g_object_get((GObject *) mobj, klass->data->query->upfield, &id, NULL);
00418
00419 do {
00420 res = mgd_query(mobj->mgd,
00421 "SELECT $s,name FROM $s WHERE id=$d AND (sitegroup in (0, $d) OR $d<>0)",
00422 upfield, parent_table, id, mgd_sitegroup(mobj->mgd), mgd_isroot(mobj->mgd));
00423
00424 if(!res || !mgd_rows(res)) {
00425 mgd_free_pool(pool);
00426 return NULL;
00427 }
00428
00429 mgd_fetch(res);
00430 id = mgd_sql2int(res, 0);
00431 pename = (gchar *)mgd_colvalue(res, 1);
00432 pename = g_strjoin("/", "", pename, NULL);
00433 path = g_strjoin("", pename, path, NULL);
00434 mgd_release(res);
00435 } while (id != 0);
00436
00437 mgd_free_pool(pool);
00438 g_log("midgard-lib", G_LOG_LEVEL_DEBUG, "PATH %s", path);
00439 return path;
00440 }
00441
00442
00443
00444 gboolean midgard_object_is_in_parent_tree(MgdObject *mobj, guint rootid, guint id)
00445 {
00446 g_assert(mobj != NULL);
00447
00448 gint ri;
00449 const gchar *parent_table, *parent_up;
00450
00451 MgdObject *parent = midgard_object_new(mobj->mgd,
00452 midgard_object_parent(mobj), NULL);
00453
00454 MidgardObjectClass *parent_class = MIDGARD_OBJECT_GET_CLASS(parent);
00455
00456 parent_table = midgard_object_class_get_table(parent_class);
00457 parent_up = parent_class->data->query->upfield;
00458
00459 g_object_unref(parent);
00460
00461 if (!parent_table)
00462 return FALSE;
00463
00464 if (!parent_up)
00465 return FALSE;
00466
00467
00468 if(!mgd_exists_id(mobj->mgd, parent_table, "id=$d", id))
00469 return FALSE;
00470
00471 if((ri = mgd_is_in_tree(mobj->mgd, parent_table,
00472 parent_up,
00473 rootid, id)))
00474 return TRUE;
00475
00476 return FALSE;
00477 }
00478
00479
00480
00481
00482 gboolean midgard_object_is_in_tree(MgdObject *mobj, guint rootid, guint id)
00483 {
00484 g_assert(mobj != NULL);
00485
00486 gint ri;
00487 const gchar *table, *upfield;
00488 MidgardObjectClass *klass = MIDGARD_OBJECT_GET_CLASS(mobj);
00489
00490 table = midgard_object_class_get_table(klass);
00491 upfield = klass->data->query->upfield;
00492
00493 if (!table)
00494 return FALSE;
00495
00496 if (!upfield)
00497 return FALSE;
00498
00499
00500 if(!mgd_exists_id(mobj->mgd, table, "id=$d", id))
00501 return FALSE;
00502
00503 if((ri = mgd_is_in_tree(mobj->mgd, table,
00504 upfield,
00505 rootid, id)))
00506 return TRUE;
00507
00508 return FALSE;
00509 }
00510
00511
00512
00513 gchar *midgard_object_get_tree(MgdObject *object, GSList *tnodes)
00514 {
00515 GValue pval = {0,};
00516 guint i;
00517 midgard_res *res = NULL;
00518 gchar *snodes = "";
00519 GParamSpec *prop;
00520
00521 MidgardObjectClass *klass = MIDGARD_OBJECT_GET_CLASS(object);
00522 const gchar *table = midgard_object_class_get_table(klass);
00523 prop = g_object_class_find_property((GObjectClass *) object->klass,
00524 (gchar *)object->data->query->primary);
00525
00526 g_value_init(&pval,prop->value_type);
00527
00528 g_object_get_property(G_OBJECT(object), g_strdup((gchar *)klass->data->primary), &pval);
00529
00530 switch(prop->value_type){
00531
00532 case G_TYPE_STRING:
00533
00534 res = mgd_query(object->mgd,
00535 "SELECT $s FROM $s WHERE $s='$s' AND (sitegroup in (0, $d) OR $d<>0)",
00536 klass->data->primary, table,
00537 klass->data->query->upfield, g_value_get_string(&pval),
00538 mgd_sitegroup(object->mgd), mgd_isroot(object->mgd));
00539 break;
00540
00541 case G_TYPE_UINT:
00542
00543 res = mgd_query(object->mgd,
00544 "SELECT $s FROM $s WHERE $s=$d AND (sitegroup in (0, $d) OR $d<>0)",
00545 klass->data->primary, table,
00546 klass->data->query->upfield, g_value_get_uint(&pval),
00547 mgd_sitegroup(object->mgd), mgd_isroot(object->mgd));
00548 break;
00549 }
00550
00551 g_value_unset(&pval);
00552
00553 if(!res || !mgd_rows(res)) {
00554 if(res) mgd_release(res);
00555 return NULL;
00556 }
00557
00558 mgd_fetch(res);
00559
00560 for (i = 0; i < mgd_cols(res); i++) {
00561
00562 switch(prop->value_type) {
00563
00564 case G_TYPE_STRING:
00565
00566 tnodes = g_slist_append(tnodes, g_strdup(mgd_colvalue(res, i)));
00567 g_object_set(G_OBJECT(object),
00568 g_strdup((gchar *)klass->data->primary), (gchar *)mgd_colvalue(res, i), NULL);
00569 break;
00570
00571 case G_TYPE_UINT:
00572
00573 tnodes = g_slist_append(tnodes, GINT_TO_POINTER (mgd_colvalue(res, i)));
00574 g_object_set(G_OBJECT(object),
00575 g_strdup((gchar *)klass->data->primary), atoi(mgd_colvalue(res, i)), NULL);
00576 break;
00577
00578 }
00579
00580 midgard_object_get_tree(object, tnodes);
00581 }
00582
00583 return snodes;
00584 }
00585