GridLab
Grid Application Toolkit

A simple API for Grid Applications
GAT

Menu



Main Page   Alphabetical List   Compound List   File List   Compound Members   File Members  

advertservice_database.c

Go to the documentation of this file.
00001 /** @file advertservice_database.c
00002  *  Source file for the database routines used to simulate a real advert 
00003  *  service.
00004  *
00005  *  @date Fri Mar 19 2004
00006  *
00007  *  @version $Header: /export/cvs-gridlab/wp-1/Codes/GATEngine/C-reference/adaptors/advertservice_adaptor/advertservice_database.c,v 1.9 2004/04/18 15:04:59 merzky Exp $
00008  *
00009  *  Copyright (C) Hartmut Kaiser
00010  *  This file is part of the GAT Engine.
00011  *  Contributed by Hartmut Kaiser <hartmutkaiser [at] t-online [dot] de>.
00012  *
00013  *  Use, modification and distribution is subject to the Gridlab Software
00014  *  License. (See accompanying file GLlicense.txt or copy at
00015  *  http://www.gridlab.org/GLlicense.txt)
00016  */
00017 
00018 static const char *rcsid = "$Header: /export/cvs-gridlab/wp-1/Codes/GATEngine/C-reference/adaptors/advertservice_adaptor/advertservice_database.c,v 1.9 2004/04/18 15:04:59 merzky Exp $";
00019  
00020 /* System Header Files */
00021 #include <stdio.h>
00022 #include <stdlib.h>
00023 #include <string.h>
00024 
00025 #include <GAT.h>
00026 #include <GATUtil.h>
00027 
00028 #include "regex.h"
00029 #include "advertservice_database.h"
00030 
00031 /* Macros */
00032 #if !defined(MAX_DB_NAME)
00033 #define MAX_DB_NAME 256
00034 #endif // !defined(MAX_DB_NAME)
00035 
00036 /* Structures, unions and enums */
00037 
00038 /* Static function prototypes */
00039 static GATResult
00040   advertservice_db_get_version(sqlite *db, GATuint32 *version, char **err_msg);
00041 
00042 static GATResult
00043   advertservice_db_execute_sql_statements(sqlite *db, char const **stmts, 
00044     char **err_msg);
00045 
00046 static GATResult
00047   advertservice_db_begin_transaction(sqlite *db, char **err_msg);
00048 
00049 static GATResult
00050   advertservice_db_commit_transaction(sqlite *db, char **err_msg);
00051 
00052 static GATResult
00053 advertservice_db_find_node(sqlite *db, char const *path, int *node_id, 
00054   GATBool createnode, char **err_msg);
00055 
00056 static GATResult
00057 advertservice_db_write_data(sqlite *db, int node_id, char const *data, 
00058   GATTable_const metadata, char **err_msg);
00059 
00060 static GATResult
00061   advertservice_db_delete_node(sqlite *db, int node_id, char **err_msg);
00062 
00063 static GATResult
00064   advertservice_db_get_node_metadata(sqlite *db, int node_id, 
00065     GATTable *metadata, char **err_msg);
00066     
00067 static GATResult
00068   advertservice_db_get_node_data(sqlite *db, int node_id, 
00069     char **advert_data, char **err_msg);
00070 
00071 static GATResult
00072 advertservice_db_find_pathes(sqlite *db, int nrows, char **values, 
00073   GATList_String node_paths, char **err_msg);
00074 
00075 static GATResult 
00076 advertservice_db_construct_path(sqlite *db, char *node_id_str, char **path, 
00077   char **err_msg);
00078 
00079 static int
00080   advertservice_db_read_node_id(sqlite *db, char const *node_name, 
00081     int parent_id, int *node_id, char **err_msg);
00082 
00083 static int
00084   advertservice_db_alter_table(sqlite *db, char const **keys, char **err_msg);
00085 
00086 static int
00087   advertservice_db_create_datatable(sqlite *db, char **old_fields, int count,
00088     char **new_fields, int table_number, char **err_msg);
00089 
00090 static int 
00091   advertservice_db_copy_datatable(sqlite *db, char **old_fields, int count,
00092     int table_number, char **err_msg);
00093 
00094 static int
00095   advertservice_db_add_metadata(sqlite *db, char **new_fields, char **err_msg);
00096 
00097 static int 
00098   advertservice_db_get_datatable_number(sqlite *db, int *number, 
00099     char **err_msg);
00100 
00101 static void 
00102   advertservice_db_re_match(sqlite_func *func, int argc, const char **argv);
00103 
00104 /* utility functions */
00105 static int
00106   append_string(char **str, char const *to_append);
00107 
00108 static unsigned int 
00109   fields_count(char **fields);
00110 
00111 static GATResult
00112   add_field(char ***fields, char const *key);
00113 
00114 static void
00115   release_fields(char ***fields);
00116 
00117 /* File scope variables */
00118 
00119 
00120 /* creation and initial population of the database */
00121 static char const *init_db_stmts[] = 
00122 {
00123   "begin transaction on conflict rollback;",
00124 
00125   /* create and populate the main table */
00126     "create table main ("
00127       "id integer primary key on conflict rollback,"
00128       "key varchar(32) not null on conflict rollback,"
00129       "value varchar(128)"
00130     ");",
00131     "insert or rollback into main (key, value) values('version', '10000');",
00132     "insert or rollback into main (key, value) values('datatable', 'data1');",
00133 
00134   /* create and populate the node table */
00135     "create table nodes ("
00136       "node_id integer primary key on conflict rollback,"
00137       "node_name,"
00138       "parent_id"           /* references key nodes(node_id) */
00139     ");",
00140     "insert or rollback into nodes (node_name, parent_id) values('__root__', NULL);",
00141 
00142   /* create the data table */
00143     "create table data1 ("
00144       "node_id unique,"     /* references key nodes(node_id) */
00145       "data"
00146     ");",
00147 
00148   /* create and populate the meta data table (this table holds all the field 
00149      names, which are in use in the current data table */
00150     "create table metadata ("
00151       "metakey not null on conflict rollback"
00152     ");",
00153 
00154   /* the table is populated with the two existing fields (which are obviously 
00155      not meta fields, but anyway ... */
00156     "insert or rollback into metadata (metakey) values('node_id');",
00157     "insert or rollback into metadata (metakey) values('data');",
00158 
00159   "commit transaction;",
00160   0
00161 };
00162 
00163 /* start a transaction */
00164 static char const *begin_transaction_stmts[] = 
00165 {
00166   "begin transaction on conflict rollback;",
00167   0
00168 };
00169 
00170 /* commit an active transaction */
00171 static char const *commit_transaction_stmts[] = 
00172 {
00173   "commit transaction;",
00174   0
00175 };
00176 
00177 /* External functions */
00178 
00179 /** advertservice_db_init
00180  *  
00181  *  Initialise the engine and create the database, if appropriate (if it 
00182  *  doesn't exist).
00183  */
00184 GATResult 
00185 advertservice_db_init(GATContext context, sqlite **db)
00186 {
00187   GAT_USES_STATUS(context, "advertservice_db_init");
00188   
00189   int result = 0;
00190   sqlite *new_db = NULL;
00191   char *err_msg = NULL;
00192   
00193   /* open/create the database file */
00194   new_db = sqlite_open("advertservice.db", 0, &err_msg);
00195   GAT_CREATE_STATUS_IF(NULL == new_db, SQLITE_TO_GAT(SQLITE_CANTOPEN));
00196   
00197   /* try to read the db version */
00198   if (GAT_SUCCEEDED(GAT_CURRENT_STATUS()))
00199   {
00200     int version = 0;
00201     GAT_CREATE_STATUS(advertservice_db_get_version(new_db, &version, &err_msg));
00202 
00203     /* database doesn't exist, recreate it */
00204     if (GAT_FAILED(GAT_CURRENT_STATUS()))
00205     {
00206       GAT_CREATE_STATUS_UNCOND(advertservice_db_execute_sql_statements(new_db, 
00207         init_db_stmts, &err_msg));
00208     }
00209   }
00210   
00211   if (NULL == db)
00212   {
00213     GAT_CREATE_STATUS(GAT_INVALID_PARAMETER);
00214   }
00215   
00216   /* attach the database diagnostics to the status object, if appropriate */  
00217   if (GAT_FAILED(GAT_CURRENT_STATUS()))
00218   {
00219     if (NULL != err_msg)
00220     {
00221       GAT_STATUS_ADD_MESSAGE(err_msg);
00222       free(err_msg);
00223     }
00224   }
00225   else 
00226   {
00227     /* return the opened database */
00228     *db = new_db;
00229   }
00230   return GAT_RETURN_STATUS();
00231 }
00232 
00233 /** advertservice_db_close
00234  *  
00235  */
00236 void
00237 advertservice_db_close(sqlite **db)
00238 {
00239   if (NULL != db && NULL != *db)
00240   {
00241     sqlite_close(*db);
00242     *db = NULL;
00243   }
00244 }
00245 
00246 /** advertservice_db_write_advert_data
00247  *  
00248  */
00249 GATResult 
00250 advertservice_db_write_advert_data(GATContext context, sqlite *db, 
00251   char const *path, char const *data, GATTable_const metadata)
00252 {
00253   GAT_USES_STATUS(context, "advertservice_db_write_advert_data");
00254   int node_id = 0;
00255   char *err_msg = NULL;
00256 
00257   /* wrap the overall operation into a transaction */
00258   GAT_CREATE_STATUS(advertservice_db_begin_transaction(db, &err_msg));
00259   
00260   /* find or create the specified node inside the nodes table */
00261   GAT_CREATE_STATUS(advertservice_db_find_node(db, path, &node_id, GATTrue,
00262     &err_msg));
00263   
00264   /* write the data and the metadata to the data table */
00265   GAT_CREATE_STATUS(advertservice_db_write_data(db, node_id, data, metadata, 
00266     &err_msg));
00267 
00268   /* all went ok, so commit the changes */
00269   GAT_CREATE_STATUS(advertservice_db_commit_transaction(db, &err_msg));
00270   
00271   /* attach the database diagnostics to the status object, if appropriate */  
00272   if (GAT_FAILED(GAT_CURRENT_STATUS()) && NULL != err_msg)
00273   {
00274     GAT_STATUS_ADD_MESSAGE(err_msg);
00275     free(err_msg);
00276   }
00277   return GAT_RETURN_STATUS();
00278 }
00279 
00280 /** advertservice_db_delete_advert_data
00281  *  
00282  */
00283 GATResult
00284 advertservice_db_delete_advert_data(GATContext context, sqlite *db, 
00285   char const *path)
00286 {
00287   GAT_USES_STATUS(context, "advertservice_db_delete_advert_data");
00288   char *err_msg = NULL;
00289   int node_id = 0;
00290   
00291   /* wrap the overall operation into a transaction */
00292   GAT_CREATE_STATUS(advertservice_db_begin_transaction(db, &err_msg));
00293   
00294   /* find the specified node inside the nodes table */
00295   GAT_CREATE_STATUS(advertservice_db_find_node(db, path, &node_id, GATFalse, 
00296     &err_msg));
00297   
00298   /* delete the node and its associated data */
00299   GAT_CREATE_STATUS(advertservice_db_delete_node(db, node_id, &err_msg));
00300   
00301   /* all went ok, so commit the changes */
00302   GAT_CREATE_STATUS(advertservice_db_commit_transaction(db, &err_msg));
00303 
00304   /* attach the database diagnostics to the status object, if appropriate */  
00305   if (GAT_FAILED(GAT_CURRENT_STATUS()) && NULL != err_msg)
00306   {
00307     GAT_STATUS_ADD_MESSAGE(err_msg);
00308     free(err_msg);
00309   }
00310   return GAT_RETURN_STATUS();
00311 }
00312 
00313 /** advertservice_db_get_metadata
00314  *  
00315  */
00316 GATResult
00317 advertservice_db_get_metadata(GATContext context, sqlite *db, 
00318   char const *path, GATTable *metadata)
00319 {
00320   GAT_USES_STATUS(context, "advertservice_db_get_metadata");
00321   char *err_msg = NULL;
00322   int node_id = 0;
00323   
00324   /* find the specified node inside the nodes table */
00325   GAT_CREATE_STATUS(advertservice_db_find_node(db, path, &node_id, GATFalse, 
00326     &err_msg));
00327   
00328   /* retrieve the associated metadata */
00329   GAT_CREATE_STATUS(advertservice_db_get_node_metadata(db, node_id, metadata, 
00330     &err_msg));
00331     
00332   /* attach the database diagnostics to the status object, if appropriate */  
00333   if (GAT_FAILED(GAT_CURRENT_STATUS()) && NULL != err_msg)
00334   {
00335     GAT_STATUS_ADD_MESSAGE(err_msg);
00336     free(err_msg);
00337   }
00338   return GAT_RETURN_STATUS();
00339 }
00340 
00341 /** advertservice_db_get_advertisable_data
00342  *  
00343  */
00344 GATResult
00345 advertservice_db_get_advert_data(GATContext context, sqlite *db, 
00346   char const *path, char **data)
00347 {
00348   GAT_USES_STATUS(context, "advertservice_db_get_metadata");
00349   char *err_msg = NULL;
00350   int node_id = 0;
00351   
00352   /* find the specified node inside the nodes table */
00353   GAT_CREATE_STATUS(advertservice_db_find_node(db, path, &node_id, GATFalse, 
00354     &err_msg));
00355   
00356   /* retrieve the associated data */
00357   GAT_CREATE_STATUS(advertservice_db_get_node_data(db, node_id, data, 
00358     &err_msg));
00359     
00360   /* attach the database diagnostics to the status object, if appropriate */  
00361   if (GAT_FAILED(GAT_CURRENT_STATUS()) && NULL != err_msg)
00362   {
00363     GAT_STATUS_ADD_MESSAGE(err_msg);
00364     free(err_msg);
00365   }
00366   return GAT_RETURN_STATUS();
00367 }
00368 
00369 /** advertservice_db_find
00370  *  
00371  */
00372 GATResult
00373 advertservice_db_find(GATContext context, sqlite *db, 
00374   GATTable_const metadata, GATList_String *paths)
00375 {
00376   GAT_USES_STATUS(context, "advertservice_db_find");
00377   char *err_msg = NULL;
00378   GATuint32 len = GATTable_Size(metadata);
00379   int result = SQLITE_OK;
00380   
00381   if (0 != len)
00382   {
00383     GATuint32 i = 0;
00384     
00385     /* construct the field of regular expressions */
00386     char buffer[256];
00387     char *sql_stmt = NULL;
00388     int table_number = 0;
00389     void **keys = GATTable_GetKeys(metadata);
00390     regex_t *regexpr = (regex_t *)malloc(len * sizeof(regex_t));
00391     GAT_CREATE_STATUS_IF(NULL == regexpr, GAT_MEMORYFAILURE);
00392 
00393     for (/**/; NULL != keys[i]; ++i)
00394     {
00395       GAT_CREATE_STATUS(GATTable_Get_String(metadata, keys[i], buffer, 
00396         sizeof(buffer)));
00397       
00398       GAT_CREATE_STATUS_IF(0 != regcomp(&regexpr[i], buffer, 0), 
00399         GAT_INVALID_PARAMETER);
00400     }
00401 
00402     if (GAT_SUCCEEDED(GAT_CURRENT_STATUS()))
00403     {
00404       /* register the user defined function */
00405       result = sqlite_create_function(db, "re_match", 2, 
00406         advertservice_db_re_match, regexpr);
00407       GAT_CREATE_STATUS_IF(SQLITE_OK != result, SQLITE_TO_GAT(result));
00408 
00409       /* query the data from the current data table */
00410       result = advertservice_db_get_datatable_number(db, &table_number, &err_msg);
00411       GAT_CREATE_STATUS_IF(SQLITE_OK != result, SQLITE_TO_GAT(result));
00412     }
00413     
00414     /* construct the query string */
00415     sprintf(buffer, "select node_id from data%d where ", table_number);
00416     GAT_CREATE_STATUS_IF(SQLITE_OK != (result = append_string(&sql_stmt, buffer)), 
00417       SQLITE_TO_GAT(result));
00418       
00419     for (i = 0; NULL != keys[i]; ++i)
00420     {
00421       sprintf(buffer, "%sre_match(%d, %s) = 1", (0 == i) ? "" : " and ", i,
00422         keys[i]);
00423       GAT_CREATE_STATUS_IF(SQLITE_OK != (result = append_string(&sql_stmt, buffer)), 
00424         SQLITE_TO_GAT(result));
00425     }      
00426     
00427     GAT_CREATE_STATUS_IF(SQLITE_OK != (result = append_string(&sql_stmt, ";")), 
00428       SQLITE_TO_GAT(result));
00429             
00430     /* execute the query and fill the results into a new GATList_String object*/
00431     {
00432       int nrows = 0;
00433       int fields = 0;
00434       char **values = NULL;
00435       GATList_String node_paths = NULL;
00436       
00437       result = sqlite_get_table(db, sql_stmt, &values, &nrows, &fields, &err_msg);
00438       GAT_CREATE_STATUS_IF(SQLITE_OK != result, SQLITE_TO_GAT(result));
00439       
00440       node_paths = GATList_String_Create();
00441       GAT_CREATE_STATUS_IF(NULL == node_paths, GAT_MEMORYFAILURE);
00442       
00443       GAT_CREATE_STATUS(advertservice_db_find_pathes(db, nrows, &values[1], 
00444         node_paths, &err_msg));
00445       
00446       if (NULL != paths)
00447       {
00448         *paths = node_paths;
00449       }
00450       else
00451       {
00452         GATList_String_Destroy(&node_paths);
00453         GAT_CREATE_STATUS(GAT_INVALID_PARAMETER);
00454       }
00455       sqlite_free_table(values);
00456     }
00457     
00458     /* free all the allocated memory */
00459     free(sql_stmt);
00460     for (i = 0; i < len; ++i)
00461     {
00462       regfree(&regexpr[i]);
00463     }
00464     free(regexpr);
00465     GATTable_ReleaseKeys(metadata, &keys);
00466   }
00467   else
00468   {
00469     GAT_CREATE_STATUS(GAT_INVALID_PARAMETER);
00470   }
00471       
00472   /* attach the database diagnostics to the status object, if appropriate */  
00473   if (GAT_FAILED(GAT_CURRENT_STATUS()) && NULL != err_msg)
00474   {
00475     GAT_STATUS_ADD_MESSAGE(err_msg);
00476     free(err_msg);
00477   }
00478   return GAT_RETURN_STATUS();
00479 }
00480 
00481 /* local functions */
00482 static GATResult
00483 advertservice_db_get_version(sqlite *db, GATuint32 *version, char **err_msg)
00484 {
00485   int nrows = 0;
00486   int fields = 0;
00487   char **values = NULL;
00488 
00489   int result = sqlite_get_table(db, 
00490     "select value from main where key = 'version';",
00491     &values, &nrows, &fields, err_msg);
00492     
00493   if (SQLITE_OK != result)
00494   { 
00495     return SQLITE_TO_GAT(result); 
00496   }
00497   
00498   assert(1 == fields && 1 == nrows);
00499   result = (1 == sscanf(values[1], "%d", version)) ? SQLITE_OK : SQLITE_NOTFOUND;
00500 
00501   sqlite_free_table(values);
00502   return SQLITE_TO_GAT(result); 
00503 }
00504 
00505 /** advertservice_db_execute_sql_statements
00506  *  
00507  */
00508 static GATResult
00509 advertservice_db_execute_sql_statements(sqlite *db, char const **stmts, 
00510   char **err_msg)
00511 {
00512   int result = SQLITE_OK;
00513   int i = 0;
00514   for(/**/; NULL != stmts[i]; ++i)
00515   {
00516     result = sqlite_exec(db, stmts[i], 0, 0, err_msg);
00517     if (SQLITE_OK != result)
00518     {
00519       break;        
00520     }
00521   }
00522   return SQLITE_TO_GAT(result);
00523 }
00524 
00525 /** advertservice_db_begin_transaction 
00526  *  
00527  */
00528 static GATResult
00529 advertservice_db_begin_transaction(sqlite *db, char **err_msg)
00530 {
00531   return advertservice_db_execute_sql_statements(db, 
00532     begin_transaction_stmts, err_msg);
00533 }
00534 
00535 /** advertservice_db_commit_transaction 
00536  *  
00537  */
00538 static GATResult
00539 advertservice_db_commit_transaction(sqlite *db, char **err_msg)
00540 {
00541   return advertservice_db_execute_sql_statements(db, 
00542     commit_transaction_stmts, err_msg);
00543 }
00544 
00545 /** advertservice_db_find_node
00546  *  
00547  */
00548 static GATResult
00549 advertservice_db_find_node(sqlite *db, char const *pathstr, int *node_id, 
00550   GATBool createnode, char **err_msg)
00551 {
00552   GATResult retval = GAT_SUCCESS;
00553   char *path = GATUtil_strdup(pathstr);
00554   
00555   if (NULL != path)
00556   {
00557     if ('/' == *path)
00558     {
00559       /* the given path must be absolute */
00560       char *node_name = strtok(path + 1, "/");
00561       int parent_id = 1;    /* the root has the node_id == 1 */
00562       int current_node_id = 0;
00563       
00564       while (NULL != node_name) {
00565         if (!strcmp(node_name, "."))
00566         {
00567           /* if the node_name is '.' simply continue */
00568           current_node_id = parent_id;
00569         }
00570         else if (!strcmp(node_name, ".."))
00571         {
00572           /* we need to step up one hierarchy level */
00573           int nrows = 0;
00574           int fields = 0;
00575           char **values = NULL;
00576           int result = SQLITE_OK;
00577 
00578           if (1 == parent_id)
00579           {
00580             retval = GAT_INVALID_PARAMETER;
00581             break;  /* there is no way to step up at root level */
00582           }
00583           
00584           result = sqlite_get_table_printf(db,
00585             "select parent_id from nodes where node_id = '%d';",
00586             &values, &nrows, &fields, err_msg, parent_id);
00587           if (SQLITE_OK != result)
00588           {
00589             retval = SQLITE_TO_GAT(result);
00590             break;
00591           }
00592           
00593           if (1 != nrows || 1 != sscanf(values[1], "%d", &current_node_id))
00594           {
00595             sqlite_free_table(values);
00596             retval = SQLITE_TO_GAT(SQLITE_NOTFOUND);
00597             break;
00598           }
00599           sqlite_free_table(values);
00600         }
00601         else
00602         {
00603           /* try to find this node */
00604           int result = advertservice_db_read_node_id(db, node_name, parent_id, 
00605             &current_node_id, err_msg);
00606           if (SQLITE_OK != result || 0 == current_node_id)
00607           {
00608             if (createnode)
00609             {
00610               /* this node does not exist, insert it into the nodes table */
00611               result = sqlite_exec_printf(db, 
00612                 "insert or rollback into nodes "
00613                 "(node_name, parent_id) values('%s', %d);",
00614                 0, 0, err_msg, node_name, parent_id);
00615 
00616               if (SQLITE_OK != result)
00617               {
00618                 retval = SQLITE_TO_GAT(result);
00619                 break;
00620               }
00621               
00622               /* now the node should exist! */
00623               result = advertservice_db_read_node_id(db, node_name, parent_id, 
00624                 &current_node_id, err_msg);
00625               if (SQLITE_OK != result || 0 == current_node_id)
00626               {
00627                 retval = SQLITE_TO_GAT(result);
00628                 break;
00629               }
00630             }
00631             else
00632             {
00633               /* node doesn't exist */
00634               retval = SQLITE_TO_GAT(SQLITE_NOTFOUND);
00635               break;
00636             }
00637           }
00638         }
00639                 
00640         /* extract next node name */
00641         node_name = strtok(NULL, "/");
00642         if (NULL != node_name)
00643         {
00644           parent_id = current_node_id;
00645           current_node_id = 0;
00646         }
00647         else
00648         {
00649           *node_id = current_node_id;
00650           break;    // this was the last path segment
00651         }
00652       } 
00653     }
00654     else
00655     {
00656       retval = GAT_INVALID_PARAMETER;
00657     }
00658     free(path);
00659   }
00660   else
00661   {
00662     retval = GAT_MEMORYFAILURE;
00663   }
00664   
00665   return retval;
00666 }
00667 
00668 static int
00669 append_string(char **str, char const *to_append)
00670 {
00671   GATBool new_string = (NULL != *str) ? GATFalse : GATTrue;
00672   unsigned int len = (NULL != *str) ? strlen(*str) + 1 : 0;
00673   char *new_str = (char *)realloc(*str, len + strlen(to_append) + 1);
00674   if (NULL == new_str)
00675   {
00676     return SQLITE_NOMEM;
00677   }
00678   if (GATTrue == new_string)
00679   {
00680     new_str[0] = '\0';
00681   }
00682   strcat(new_str, to_append);
00683   *str = new_str;
00684   return SQLITE_OK;
00685 }
00686 
00687 /** advertservice_db_write_data
00688  *  
00689  */
00690 static GATResult
00691 advertservice_db_write_data(sqlite *db, int node_id, char const *data, 
00692   GATTable_const metadata, char **err_msg)
00693 {
00694   int result = SQLITE_OK;
00695   int table_number = 0;
00696   
00697   if (NULL != metadata) 
00698   {
00699     void **keys = GATTable_GetKeys(metadata);
00700   
00701     result = advertservice_db_alter_table(db, (char const **)keys, err_msg);
00702     GATTable_ReleaseKeys(metadata, &keys);
00703     if (SQLITE_OK != result)
00704     {
00705       return SQLITE_TO_GAT(result);
00706     }
00707   }
00708   
00709   /* write the data in the current data table */
00710   result = advertservice_db_get_datatable_number(db, &table_number, err_msg);
00711   if (SQLITE_OK != result)
00712   {
00713     return SQLITE_TO_GAT(result);
00714   }
00715   result = sqlite_exec_printf(db, 
00716     "insert or replace into data%d (node_id, data) values('%d', '%q');",
00717     0, 0, err_msg, table_number, node_id, data);
00718   if (SQLITE_OK != result)
00719   {
00720     return SQLITE_TO_GAT(result);
00721   }
00722 
00723   /* insert the metadata into the new data table */
00724   if (NULL != metadata)
00725   {
00726     void **keys = GATTable_GetKeys(metadata);
00727     
00728     if (NULL != keys[0])
00729     {
00730       char buffer[256];
00731       int i = 0;
00732       char *sql_stmt = NULL;
00733       
00734       sprintf(buffer, "update or rollback data%d set ", table_number);
00735       result = append_string(&sql_stmt, buffer);
00736       if (SQLITE_OK != result)
00737       {
00738         GATTable_ReleaseKeys(metadata, &keys);
00739         return SQLITE_TO_GAT(result);
00740       }
00741 
00742       for (i = 0; NULL != keys[i]; ++i)
00743       {
00744         char value[256];
00745         
00746         if (GAT_SUCCEEDED(GATTable_Get_String(metadata, keys[i], value, 
00747               sizeof(value))))
00748         {
00749           sprintf(buffer, "%s%s = '%s'", (0 == i) ? "" : ", ", keys[i], value);
00750           result = append_string(&sql_stmt, buffer);
00751           if (SQLITE_OK != result)
00752           {
00753             GATTable_ReleaseKeys(metadata, &keys);
00754             return SQLITE_TO_GAT(result);
00755           }
00756         }
00757       }
00758       GATTable_ReleaseKeys(metadata, &keys);
00759       
00760       sprintf(buffer, " where node_id = '%d';", node_id);
00761       result = append_string(&sql_stmt, buffer);
00762       if (SQLITE_OK != result)
00763       {
00764         return SQLITE_TO_GAT(result);
00765       }
00766 
00767       result = sqlite_exec(db, sql_stmt, 0, 0, err_msg);
00768       free(sql_stmt);
00769     }
00770     else
00771     {
00772       /* at least one metadata key/value pair should be supplied */
00773       GATTable_ReleaseKeys(metadata, &keys);
00774       return GAT_INVALID_PARAMETER;
00775     }
00776   }
00777 
00778   return SQLITE_TO_GAT(result);
00779 }
00780 
00781 /** advertservice_db_read_node_id
00782  *  
00783  */
00784 static int
00785 advertservice_db_read_node_id(sqlite *db, char const *node_name, int parent_id,
00786   int *node_id, char **err_msg)
00787 {
00788   int result = SQLITE_OK;
00789   int nrows = 0;
00790   int fields = 0;
00791   char **values = NULL;
00792   
00793   result = sqlite_get_table_printf(db, 
00794     "select node_id from nodes "
00795     "where node_name = '%s' and parent_id = %d", 
00796     &values, &nrows, &fields, err_msg,
00797     node_name, parent_id);
00798 
00799   if (SQLITE_OK == result && 0 != nrows)
00800   {
00801     assert(1 == nrows && 1 == fields);
00802     result = (1 == sscanf(values[1], "%d", node_id)) ? SQLITE_OK : SQLITE_NOTFOUND;
00803   }
00804 
00805   sqlite_free_table(values);
00806   return result;
00807 }        
00808 
00809 static unsigned int 
00810 fields_count(char **fields)
00811 {
00812   unsigned int i = 0;
00813   if (NULL != fields)
00814   {
00815     while(NULL != fields[i])
00816     {
00817       ++i;
00818     }
00819   }
00820   return i;
00821 }
00822 
00823 static GATResult
00824 add_field(char ***fields, char const *key)
00825 {
00826   unsigned int count = fields_count(*fields);
00827   char **new_fields = (char **)realloc(*fields, (count + 2) * sizeof(char *));
00828   
00829   if (NULL == new_fields)
00830   {
00831     return GAT_MEMORYFAILURE;
00832   }
00833   
00834   *fields = new_fields;
00835   (*fields)[count] = GATUtil_strdup(key);
00836   if (NULL == (*fields)[count])
00837   {
00838     return GAT_MEMORYFAILURE;
00839   }
00840   
00841   (*fields)[count+1] = NULL;
00842   return GAT_SUCCESS;
00843 }
00844 
00845 static void
00846 release_fields(char ***fields)
00847 {
00848   if (NULL != fields && NULL != *fields)
00849   {
00850     int i = 0;
00851     for (/**/; NULL != (*fields)[i]; ++i)
00852     {
00853       free((*fields)[i]);
00854     }
00855     free(*fields);
00856     *fields = NULL;
00857   }
00858 }
00859 
00860 /** advertservice_db_alter_table
00861  *  
00862  *  Since the SQLite database doesn't support the ALTER TABLE SQL command, we 
00863  *  have to create a new table with the required structure and must copy over
00864  *  the old data to the new table. The old table is dropped afterwards.
00865  */
00866 static int
00867 advertservice_db_alter_table(sqlite *db, char const **keys, char **err_msg)
00868 {
00869   int result = SQLITE_OK;
00870   int old_fields_nrows = 0;
00871   int old_fields_count = 0;
00872   char **old_fields = NULL;
00873   char **new_fields = NULL;
00874   int i = 0;
00875   int j = 1;
00876   int table_number = 0;
00877   
00878   /* get the names of the fields currently in use */
00879   result = sqlite_get_table(db, "select metakey from metadata;",
00880     &old_fields, &old_fields_nrows, &old_fields_count, err_msg);
00881   if (SQLITE_OK != result || 0 == old_fields_nrows)
00882   {
00883     return result;
00884   }
00885   
00886   /* find the key names, which are new to the metadata table */
00887   for (/**/; NULL != keys[i] ; ++i)
00888   {
00889     GATBool found = GATFalse;
00890     for (j = 1; j < old_fields_nrows + old_fields_count; ++j)
00891     {
00892       if (!strcmp(keys[i], old_fields[j]))
00893       {
00894         found = GATTrue;
00895         break;
00896       }
00897     }
00898     /* if this key name isn't known to us, store it */
00899     if (GATFalse == found)
00900     {
00901       add_field(&new_fields, keys[i]);
00902     }    
00903   }
00904   if (NULL == new_fields)
00905   {
00906     /* no new fields required ! */
00907     sqlite_free_table(old_fields);
00908     return SQLITE_OK;
00909   }
00910   
00911   /* generate the name of the new data table */
00912   result = advertservice_db_get_datatable_number(db, &table_number, err_msg);
00913   if (SQLITE_OK != result)
00914   {
00915     sqlite_free_table(old_fields);
00916     release_fields(&new_fields);
00917     return result;
00918   }
00919 
00920   /* create the new table */
00921   result = advertservice_db_create_datatable(db, &old_fields[1], 
00922     old_fields_nrows, new_fields, table_number+1, err_msg);
00923   if (SQLITE_OK != result)
00924   {
00925     sqlite_free_table(old_fields);
00926     release_fields(&new_fields);
00927     return result;
00928   }
00929   
00930   /* copy over the data to the new table */
00931   result = advertservice_db_copy_datatable(db, &old_fields[1], 
00932     old_fields_nrows, table_number, err_msg);
00933   sqlite_free_table(old_fields);
00934   if (SQLITE_OK != result)
00935   {
00936     release_fields(&new_fields);
00937     return result;
00938   }
00939   
00940   /* insert the new field names into the meta table */
00941   result = advertservice_db_add_metadata(db, new_fields, err_msg);
00942   release_fields(&new_fields);
00943   if (SQLITE_OK != result)
00944   {
00945     return result;
00946   }
00947   
00948   /* drop the original table */
00949   result = sqlite_exec_printf(db, "drop table data%d;", 0, 0, err_msg,  
00950     table_number);
00951   if (SQLITE_OK != result)
00952   {
00953     return result;
00954   }
00955       
00956   /* save the name of the new table in the main table */
00957   result = sqlite_exec_printf(db, 
00958     "update or rollback main set value = 'data%d' where key = 'datatable';",
00959     0, 0, err_msg, table_number + 1);
00960   if (SQLITE_OK != result)
00961   {
00962     return result;
00963   }
00964 
00965   return result;
00966 }
00967 
00968 /** advertservice_db_create_datatable
00969  *  
00970  */
00971 static int
00972 advertservice_db_create_datatable(sqlite *db, char **old_fields, int count,
00973   char **new_fields, int table_number, char **err_msg)
00974 {
00975   int result = SQLITE_OK;
00976   char *sql_stmt = NULL;
00977   char buffer[256];
00978   int i = 0;
00979   
00980   /* construct the sql statement */
00981   sprintf(buffer, "create table data%d (", table_number);
00982   result = append_string(&sql_stmt, buffer);
00983   if (SQLITE_OK != result)
00984   {
00985     return result;
00986   }
00987   
00988   /* append the old meta fields */
00989   for (/**/; i < count; ++i)
00990   {
00991     if (!strcmp(old_fields[i], "node_id") || !strcmp(old_fields[i], "data"))
00992     {
00993       continue;
00994     }
00995     
00996     sprintf(buffer, "%s, ", old_fields[i]);
00997     result = append_string(&sql_stmt, buffer);
00998     if (SQLITE_OK != result)
00999     {
01000       free(sql_stmt);
01001       return result;
01002     }
01003   }
01004   
01005   /* append the new meta fields */
01006   for (i = 0; NULL != new_fields[i]; ++i)
01007   {
01008     sprintf(buffer, "%s, ", new_fields[i]);
01009     result = append_string(&sql_stmt, buffer);
01010     if (SQLITE_OK != result)
01011     {
01012       free(sql_stmt);
01013       return result;
01014     }
01015   }
01016   
01017   /* append the required data fields */
01018   result = append_string(&sql_stmt, "node_id unique, data);");
01019   if (SQLITE_OK != result)
01020   {
01021     return result;
01022   }
01023   
01024   /* execute the constructed sql statement */
01025   result = sqlite_exec(db, sql_stmt, 0, 0, err_msg);
01026   free (sql_stmt);
01027   
01028   return result;
01029 }
01030 
01031 /** advertservice_db_copy_datatable
01032  *  
01033  */
01034 static int 
01035 advertservice_db_copy_datatable(sqlite *db, char **old_fields, int count,
01036   int table_number, char **err_msg)
01037 {
01038   int result = SQLITE_OK;
01039   char buffer[256];
01040   char *sql_stmt = NULL;
01041   int i = 0;
01042       
01043   sprintf(buffer, "insert or rollback into data%d (", table_number+1);
01044   result = append_string(&sql_stmt, buffer);
01045   if (SQLITE_OK != result)
01046   {
01047     return result;
01048   }
01049 
01050   /* append the old meta fields */
01051   for (/**/; i < count; ++i)
01052   {
01053     if (!strcmp(old_fields[i], "node_id") || !strcmp(old_fields[i], "data"))
01054     {
01055       continue;
01056     }
01057     sprintf(buffer, "%s, ", old_fields[i]);
01058     result = append_string(&sql_stmt, buffer);
01059     if (SQLITE_OK != result)
01060     {
01061       free(sql_stmt);
01062       return result;
01063     }
01064   }
01065   
01066   result = append_string(&sql_stmt, "node_id, data) select ");
01067   if (SQLITE_OK != result)
01068   {
01069     return result;
01070   }
01071 
01072   for (i = 0; i < count; ++i)
01073   {
01074     if (!strcmp(old_fields[i], "node_id") || !strcmp(old_fields[i], "data"))
01075     {
01076       continue;
01077     }
01078     sprintf(buffer, "%s, ", old_fields[i]);
01079     result = append_string(&sql_stmt, buffer);
01080     if (SQLITE_OK != result)
01081     {
01082       free(sql_stmt);
01083       return result;
01084     }
01085   }
01086   
01087   sprintf(buffer, "node_id, data from data%d;", table_number);
01088   result = append_string(&sql_stmt, buffer);
01089   if (SQLITE_OK != result)
01090   {
01091     return result;
01092   }
01093   
01094   /* execute the constructed sql command */
01095   result = sqlite_exec(db, sql_stmt, 0, 0, err_msg);
01096   free(sql_stmt);
01097     
01098   return result;
01099 }
01100 
01101 /** advertservice_db_add_metadata
01102  *  
01103  */
01104 static int
01105 advertservice_db_add_metadata(sqlite *db, char **new_fields, char **err_msg)
01106 {
01107   int result = SQLITE_OK;
01108   int i = 0;
01109   
01110   for (i = 0; NULL != new_fields[i]; ++i)
01111   {
01112     result = sqlite_exec_printf(db,
01113       "insert or rollback into metadata (metakey) values('%s');",
01114       0, 0, err_msg, new_fields[i]);
01115     if (SQLITE_OK != result)
01116     {
01117       break;
01118     }
01119   }
01120   return result;
01121 }
01122 
01123 /** advertservice_db_get_datatable_number
01124  *  
01125  */
01126 static int 
01127 advertservice_db_get_datatable_number(sqlite *db, int *number, char **err_msg)
01128 {
01129   int result = SQLITE_OK;
01130   int nrows = 0;
01131   int fields = 0;
01132   char **values = NULL;
01133 
01134   *number = 0;
01135     
01136   /* generate the name of the new data table */
01137   result = sqlite_get_table_printf(db, 
01138     "select value from main where key = 'datatable';",
01139     &values, &nrows, &fields, err_msg);
01140   if (SQLITE_OK != result || 1 != nrows)
01141   {
01142     return result;
01143   }
01144   if (1 != sscanf(values[1], "data%d", number))
01145   {
01146     sqlite_free_table(values);
01147     return SQLITE_NOTFOUND;
01148   }
01149   sqlite_free_table(values);
01150 
01151   return SQLITE_OK;
01152 }
01153 
01154 /** advertservice_db_delete_node
01155  *  
01156  */
01157 static GATResult
01158 advertservice_db_delete_node(sqlite *db, int node_id, char **err_msg)
01159 {
01160   int result = SQLITE_OK;
01161   int nrows = 0;
01162   int fields = 0;
01163   char **values = NULL;
01164   int table_number = 0;
01165   
01166   /* delete the node, if it has no child nodes */
01167   result = sqlite_get_table_printf(db, 
01168     "select node_id from nodes where parent_id = '%d';",
01169     &values, &nrows, &fields, err_msg, node_id);
01170   sqlite_free_table(values);
01171   if (SQLITE_OK != result)
01172   {
01173     return SQLITE_TO_GAT(result);
01174   }
01175   
01176   if (0 == nrows)
01177   {
01178     /* this node has no child nodes */
01179     result = sqlite_exec_printf(db, 
01180       "delete from nodes where node_id = '%d';",
01181       0, 0, err_msg, node_id);
01182     if (SQLITE_OK != result)
01183     {
01184       return SQLITE_TO_GAT(result);
01185     }
01186 
01187     /* FIXME: here we should remove all empty nodes above the node to delete */
01188   }
01189   
01190   /* get the current name of the data table */
01191   result = advertservice_db_get_datatable_number(db, &table_number, err_msg);
01192   if (SQLITE_OK != result)
01193   {
01194     return SQLITE_TO_GAT(result);
01195   }
01196 
01197   /* delete the corresponding data from the data table */
01198   result = sqlite_exec_printf(db, 
01199     "delete from data%d where node_id = '%d';",
01200     0, 0, err_msg, table_number, node_id);
01201     
01202   /* FIXME: here we should remove the fields (metadata keys), which aren't used
01203      anymore after deleting the data record for this node 
01204    */
01205 
01206   return SQLITE_TO_GAT(result);
01207 }
01208 
01209 /** advertservice_db_get_node_metadata
01210  *  
01211  */
01212 static GATResult
01213 advertservice_db_get_node_metadata(sqlite *db, int node_id, 
01214   GATTable *metadata, char **err_msg)
01215 {
01216   GATResult retval = GAT_SUCCESS;
01217   int result = SQLITE_OK;
01218   int table_number = 0;
01219   int nrows = 0;
01220   int fields = 0;
01221   char **values = NULL;
01222   GATTable table = NULL;
01223   int i = 0;
01224   
01225   /* get the current name of the data table */
01226   result = advertservice_db_get_datatable_number(db, &table_number, err_msg);
01227   if (SQLITE_OK != result)
01228   {
01229     return SQLITE_TO_GAT(result);
01230   }
01231 
01232   /* get the complete record for the given node */
01233   result = sqlite_get_table_printf(db, 
01234     "select * from data%d where node_id = '%d';",
01235     &values, &nrows, &fields, err_msg, table_number, node_id);
01236   if (SQLITE_OK != result)
01237   {
01238     return SQLITE_TO_GAT(result);
01239   }
01240 
01241   /* create the metadata table */
01242   table = GATTable_Create();
01243   if (NULL == table)
01244   {
01245     sqlite_free_table(values);
01246     return GAT_MEMORYFAILURE;
01247   }
01248   
01249   /* copy all the non empty metadata values into the table */
01250   for (i = 0; i < fields; ++i)
01251   {
01252     /* skip the standard fields */
01253     if (NULL == values[i+fields] ||  /* skip fields with NULL value */
01254         !strcmp(values[i], "node_id") || !strcmp(values[i], "data"))
01255     {
01256       continue;
01257     }
01258     
01259     retval = GATTable_Add_String(table, values[i], values[i+fields]);
01260     if (GAT_FAILED(retval))
01261     {
01262       break;
01263     }
01264   }
01265 
01266   /* return the filled metadata Table */
01267   if (GAT_SUCCEEDED(retval))
01268   {
01269     if (NULL != metadata)
01270     {
01271       *metadata = table;    
01272     }
01273     else
01274     {
01275       retval = GAT_INVALID_PARAMETER;
01276       GATTable_Destroy(&table);
01277     }
01278   }
01279   else
01280   {
01281     GATTable_Destroy(&table);
01282   }
01283   sqlite_free_table(values);
01284   return retval;
01285 }
01286     
01287 /** advertservice_db_get_node_metadata
01288  *  
01289  */
01290 static GATResult
01291 advertservice_db_get_node_data(sqlite *db, int node_id, 
01292   char **advert_data, char **err_msg)
01293 {
01294   GATResult retval = GAT_SUCCESS;
01295   int result = SQLITE_OK;
01296   int table_number = 0;
01297   int nrows = 0;
01298   int fields = 0;
01299   char **values = NULL;
01300   char *data = NULL;
01301   
01302   /* get the current name of the data table */
01303   result = advertservice_db_get_datatable_number(db, &table_number, err_msg);
01304   if (SQLITE_OK != result)
01305   {
01306     return SQLITE_TO_GAT(result);
01307   }
01308 
01309   /* get the data for the given node */
01310   result = sqlite_get_table_printf(db, 
01311     "select data from data%d where node_id = '%d';",
01312     &values, &nrows, &fields, err_msg, table_number, node_id);
01313   if (SQLITE_OK != result)
01314   {
01315     return SQLITE_TO_GAT(result);
01316   }
01317 
01318   /* simply copy the data from the resultset */
01319   data = GATUtil_strdup(values[1]);
01320   if (NULL == data)
01321   {
01322     return GAT_MEMORYFAILURE;
01323   }
01324   
01325   /* return the filled metadata Table */
01326   if (GAT_SUCCEEDED(retval))
01327   {
01328     if (NULL != advert_data)
01329     {
01330       *advert_data = data;    
01331     }
01332     else
01333     {
01334       retval = GAT_INVALID_PARAMETER;
01335       free(data);
01336     }
01337   }
01338   else
01339   {
01340     free(data);
01341   }
01342   sqlite_free_table(values);
01343   return retval;
01344 }
01345 
01346 /** advertservice_db_re_match
01347  *  
01348  *  User defined SQL function re_match()
01349  */    
01350 static void 
01351 advertservice_db_re_match(sqlite_func *func, int argc, const char **argv)
01352 {
01353   if (2 != argc)
01354   {
01355     sqlite_set_result_error(func, "re_match: expected exactly 2 parameters", 
01356       SQLITE_MISUSE);
01357   }
01358   else
01359   {
01360     int result = REG_NOMATCH;
01361     int regexpr_num = 0;
01362     regex_t *regexpr = NULL;
01363     
01364     if (1 == sscanf(argv[0], "%d", &regexpr_num))
01365     {
01366       regexpr = (regex_t *)sqlite_user_data(func);
01367       result = regexec(&regexpr[regexpr_num], argv[1], 0, NULL, 0);
01368       if (REG_NOERROR != result && REG_NOMATCH != result)
01369       {
01370         /* generate an appropriate regex error message */
01371         char buffer[512];
01372         char error_msg[256];
01373         GATuint32 written = 0;
01374         GATResult retval = GATSelf_ResolveErrorMessage(REGEX_TO_GAT(result), 
01375           error_msg, sizeof(error_msg), &written);
01376 
01377         if (GAT_SUCCEEDED(retval))
01378         {
01379           sprintf(buffer, 
01380             "re_match: unexpected regular expression error: %d (%s)",
01381             result, error_msg);
01382         }
01383         else
01384         {
01385           sprintf(buffer, 
01386             "re_match: unexpected regular expression error: %d (unknown error)",
01387             result);
01388         }
01389         sqlite_set_result_error(func, buffer, SQLITE_MISUSE);
01390       }
01391       else
01392       {
01393         /* all went well, return the result */
01394         sqlite_set_result_int(func, (REG_NOERROR == result) ? 1 : 0);
01395       }
01396     }
01397     else
01398     {
01399       sqlite_set_result_error(func, 
01400         "re_match: first parameter should be of integer type", SQLITE_MISUSE);
01401     }
01402   }
01403 }
01404 
01405 /** advertservice_db_find_pathes
01406  *  
01407  */
01408 static GATResult
01409 advertservice_db_find_pathes(sqlite *db, int nrows, char **values, 
01410   GATList_String node_paths, char **err_msg)
01411 {
01412   GATResult retval = SQLITE_TO_GAT(SQLITE_NOTFOUND);
01413   int i = 0;
01414   
01415   if (0 < nrows)
01416   {
01417     /* resolve all given node_id's */
01418     for (/**/; i < nrows; ++i)
01419     {
01420       char *path = NULL;
01421       
01422       retval = advertservice_db_construct_path(db, values[i], &path, err_msg);
01423       if (GAT_SUCCEEDED(retval))
01424       {
01425         /* remove the trailing '/' */
01426         path[strlen(path)-1] = '\0';
01427         GATList_String_Insert(node_paths, GATList_String_End(node_paths), path);
01428       }
01429       free(path);
01430     }
01431   }
01432   return retval;
01433 }
01434 
01435 /** advertservice_db_construct_path
01436  *  
01437  */
01438 static GATResult 
01439 advertservice_db_construct_path(sqlite *db, char *node_id_str, char **path, 
01440   char **err_msg)
01441 {
01442   GATResult retval = GAT_SUCCESS;
01443   
01444   int node_id = 0;
01445   if (1 != sscanf(node_id_str, "%d", &node_id))
01446   {
01447     /* node_id's should be integer! */
01448     retval = GAT_INVALID_PARAMETER;
01449   }
01450   else if (1 == node_id)
01451   {
01452     /* root node */
01453     if (SQLITE_OK != append_string(path, "/"))
01454     {
01455       retval = GAT_MEMORYFAILURE;
01456     }
01457   }
01458   else
01459   {
01460     /* intermediate node, try to find the parent node and recure ... */
01461     int nrows = 0;
01462     int fields = 0;
01463     char **values = NULL;
01464     int result = sqlite_get_table_printf(db, 
01465       "select node_name, parent_id from nodes where node_id = '%d';", 
01466       &values, &nrows, &fields, err_msg, node_id);
01467     
01468     if (SQLITE_OK != result)
01469     {
01470       retval = SQLITE_TO_GAT(result);
01471     } 
01472     else if (1 != nrows)
01473     {
01474       /* node was not found in nodes table */
01475       retval = SQLITE_TO_GAT(SQLITE_NOTFOUND);   /* should not happen! */
01476     }
01477     else 
01478     {
01479       /* values[3]: parent_id */
01480       retval = advertservice_db_construct_path(db, values[3], path, err_msg);
01481       if (GAT_SUCCEEDED(retval))
01482       {
01483         /* values[2]: node_name */
01484         if (SQLITE_OK != append_string(path, values[2]) ||
01485             SQLITE_OK != append_string(path, "/"))
01486         {
01487           retval = GAT_MEMORYFAILURE;
01488         }
01489       }
01490     }
01491     
01492     /* free the allocated table data */
01493     sqlite_free_table(values);
01494   }    
01495   return retval;
01496 }