modules/ud/ud_core.c

/* [<][>]
[^][v][top][bottom][index][help] */

FUNCTIONS

This source file includes following functions.
  1. s_split
  2. s_splitn
  3. expand_rt
  4. convert_if
  5. convert_in
  6. convert_rf
  7. convert_as
  8. convert_as_range
  9. convert_time
  10. get_object_id
  11. get_field_str
  12. get_sequence_id
  13. get_ref_id
  14. isnichandle
  15. sql_info
  16. get_set_name
  17. auth_member_of
  18. create_dummy
  19. update_attr
  20. each_attribute_process
  21. each_primary_key_select
  22. perform_create
  23. perform_update
  24. object_process

/***************************************
  $Revision: 1.5 $

  Core functions for update lower layer 

  Status: NOT REVUED, NOT TESTED

 Author(s):       Chris Ottrey, Andrei Robachevsky

  ******************/ /******************
  Modification History:
        andrei (17/01/2000) Created.
  ******************/ /******************
  Copyright (c) 2000                              RIPE NCC
 
  All Rights Reserved
  
  Permission to use, copy, modify, and distribute this software and its
  documentation for any purpose and without fee is hereby granted,
  provided that the above copyright notice appear in all copies and that
  both that copyright notice and this permission notice appear in
  supporting documentation, and that the name of the author not be
  used in advertising or publicity pertaining to distribution of the
  software without specific, written prior permission.
  
  THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
  AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
  DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
  AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 ***************************************/
#include "ud.h"
#include "ud_int.h"
#include "UD_queries.def" 

char * const Type2main[] = {
"as_block",
"as_set",
"aut_num",
"domain",
"inet_rtr",
"inet6num",
"inetnum",
"key_cert",
"limerick",
"mntner",
"person_role", //pn
"person_role", //ro
"route",
"route_set",
NULL
}; /* Main tables names for object types */


static int perform_update(Transaction_t *tr);

static int perform_create(Transaction_t *tr);

static void each_primary_key_select(void *element_data, void *result_ptr);

static void each_attribute_process(void *element_data, void *tr_ptr);

static int update_attr(Attribute_t *attr, Transaction_t *tr);

static int create_dummy(Attribute_t *attr, Transaction_t *tr);

static int auth_member_of(Attribute_t *attr, Transaction_t *tr);





/***************************************************
* char *s_split(char *line)                        *
*                                                  *
* Consequently returns words of the 'line'         * 
* When there are no words it returns NULL          *
* You need to retreive all words !                 *
*                                                  *
* NB This function damages 'line' replacing        *
* whitespace with '\0'                             *
* *************************************************/
static char *s_split(char *line)
/* [<][>][^][v][top][bottom][index][help] */
{
static char *delim;
static char *token=NULL;

 if(token==NULL)token=line;
 else token=delim;
 
 if(token==NULL)return(token);
 while(isspace((int)*token))token++;
 delim=token;
 
 while(!isspace((int)*delim)) {
        if((*delim)=='\0'){
                if(delim==token)token=NULL;
                delim=NULL; return(token);
        }
        delim++;
 }
 *delim='\0'; delim++;
 return(token);

}

/* The same as s_split() but returns nwords words */
/*  and the rest of the line                      */
static char *s_splitn(char *line, int nwords)
/* [<][>][^][v][top][bottom][index][help] */
{
static char *delim;
static char *token=NULL;
static int w=0;

 
 if(token==NULL)token=line;
 else token=delim;
 
 w++; if(w>nwords){ w=0; delim=token; token=NULL; return(delim); }
 
 if(token==NULL)return(token);
 while(isspace((int)*token))token++;
 delim=token;
 
 while(!isspace((int)*delim)) {
        if((*delim)=='\0'){
                if(delim==token)token=NULL;
                delim=NULL; return(token);
        }
        delim++;
 }
 *delim='\0'; delim++;
 return(token);


}

/**********************************************************
* Attribute expansion/conversion functions                *
***********************************************************/

/* Convert route attribute into numbers */
er_ret_t expand_rt(char *avalue, unsigned int *prefix, unsigned int *prefix_length)
/* [<][>][^][v][top][bottom][index][help] */
{
ip_prefix_t pref;
er_ret_t ret;

 ret = IP_pref_e2b(&pref, avalue);
 *prefix = pref.ip.words[0];
 *prefix_length=pref.bits;
 return(ret);
}

/* Convert ifaddr attribute into numbers */
er_ret_t convert_if(char *avalue, unsigned int *address)
/* [<][>][^][v][top][bottom][index][help] */
{
char *delim;
ip_addr_t ipaddr;
er_ret_t ret;

  if ((delim=index(avalue, ' '))!=NULL) *delim='\0';
  ret = IP_addr_e2b(&ipaddr, avalue);
  *address = ipaddr.words[0];
  return(ret);
}

/* Convert inetnum attribute into numbers */
er_ret_t convert_in(char *rangstr, unsigned int *begin_in, unsigned int *end_in)
/* [<][>][^][v][top][bottom][index][help] */
{
ip_range_t myrang;
er_ret_t ret;

  if( IP_rang_e2b(&myrang, rangstr) != IP_OK ) {
// see if's a valid IP, maybe it's an IPv4 classful range
   if( IP_addr_e2b( &myrang.begin, rangstr ) == IP_OK )
     if ((ret=IP_rang_classful( &myrang , &myrang.begin )) != IP_OK ) return (ret);
  }
  *begin_in=myrang.begin.words[0];
  *end_in=myrang.end.words[0];
  return(IP_OK);
}

/* Convert refer attribute. Free host after use ! */
char *convert_rf(char *avalue, int *type, int *port)
/* [<][>][^][v][top][bottom][index][help] */
{
char *delim, *token;
char buff[STR_M];
char *host;

  host=NULL;
  strcpy(buff, avalue);
  g_strchug(buff);
  delim=index(buff, ' ');
  *delim='\0';
  delim++; 

// convert the type      
  if(strcmp(buff, S_RIPE)==0)*type=RF_RIPE;
   else if(strcmp(buff, S_INTERNIC)==0)*type=RF_INTERNIC;
    else if(strcmp(buff, S_SIMPLE)==0)*type=RF_SIMPLE;

  token=delim;
  g_strchug(token);
  delim=index(token, ' ');
  if(delim){
   *delim='\0';
   delim++; 
  }           
// convert the hostname      
  host = g_strdup(token);
      
// convert port number      
  if(delim){
    token=delim;        
    *port = atoi(token);
    if (*port==0) *port=RF_DEF_PORT; // default port number
  } else *port=RF_DEF_PORT;
  return(host);
}


/* Convert AS# into integer */
static int convert_as(char *as)
/* [<][>][^][v][top][bottom][index][help] */
{
char *ptr;
 ptr=as; ptr++; ptr++; 
 return(atoi(ptr));   
}

/* Convert AS range (AS4321 - AS5672) into numbers */
int convert_as_range(const char *as_range, int *begin, int *end)
/* [<][>][^][v][top][bottom][index][help] */
{
char buf[STR_M];
  strcpy(buf, as_range); //save it
  *begin=convert_as(s_split(buf));
  s_split(buf); // should be '-'
  *end=convert_as(s_split(buf));
  while(s_split(buf));
  return(0);
}

/* Convert time in ASCII format (19991224) into time_t unix time */
time_t convert_time(char *asc_time)
/* [<][>][^][v][top][bottom][index][help] */
{
struct tm tm;
char buf[STR_S];
char *ptr;

  
  bzero(&tm, sizeof(tm));
  
  strncpy(buf, asc_time, 4); ptr=buf+4; *ptr='\0';
  tm.tm_year = atoi(buf) - 1900;
  
  strncpy(buf, (asc_time+4), 2); ptr=buf+2; *ptr='\0';
  tm.tm_mon = atoi(buf) - 1;
  
  strncpy(buf, (asc_time+6), 2); ptr=buf+2; *ptr='\0';
  tm.tm_mday = atoi(buf);
  
  return(mktime(&tm));

}     

/*********************************
* M I S C ***********************/

/************************************************************
* long get_object_id()                                      *
* Queries the database for an object.                       *
* For constructing a query uses each__primary_key_select()  *
*                                                           *
* Returns:                                                  *
* >0 - object exists, returns object_id                     *
* 0  - object does not exist                                *
* -1 - DB error (f.e. more than one object with the same PK)     *
*                                                           *
* **********************************************************/
long get_object_id(Transaction_t *tr)
/* [<][>][^][v][top][bottom][index][help] */
{
Object_t *obj=tr->object;
SQ_result_set_t *sql_result;
SQ_row_t *sql_row;
char *sql_str;
GString *query;
long object_id=0;

 if ((query = g_string_sized_new(STR_XL)) == NULL){ 
  fprintf(stderr, "E: cannot allocate gstring\n"); 
  tr->succeeded=0;
  tr->error |= ERROR_U_MEM;
  return(ERROR_U_MEM); 
 }
 
 g_string_sprintf(query, "SELECT * FROM %s WHERE",Type2main[obj->type]);
 g_slist_foreach(obj->attributes, each_primary_key_select, query);
/* truncate the last ' AND '*/
 g_string_truncate(query, (query->len) - 4); 
        
/* execute query */
 sql_result=SQ_execute_query(SQ_STORE, tr->sql_connection, query->str);
 g_string_free(query, TRUE);
 
 if(sql_result == NULL) {
   fprintf(stderr,"ERROR: %s\n", SQ_error(tr->sql_connection));
   return(-1);
 }

 if ((sql_row = SQ_row_next(sql_result)) != NULL) {
/* Object exists */
   sql_str = SQ_get_column_string(sql_result, sql_row, OBJECT_ID);
   if (sql_str != NULL) {
     object_id = atol(sql_str);
     free(sql_str);
   }

/* We must process all the rows of the result */
/* otherwise we'll have them as part of the next qry */      
   while ( (sql_row = SQ_row_next(sql_result)) != NULL) object_id=-1;
 } else 
      object_id=0;  // object does not exist
   
 if(sql_result)SQ_free_result(sql_result);
 return(object_id);
}

/************************************************************
* get_field_str()                                           *
*                                                           *
* Returns string containing the field.                      *
*  field - field name to be retrieved                       *
*  ref_tbl_name - name of the table containing the field    *
*  ref_name - reference name                                *
*  attr_value - reference value                             *
*  condition - additional condition ( f.e. 'AND dummy=0'    *
*                                                           *
* Returns:                                                  *
*  String containing the field. Needs to be freed after use *
*  NULL in case of an error                                 *
*                                                           *
*************************************************************/
char *get_field_str(Transaction_t *tr, char *field, 
/* [<][>][^][v][top][bottom][index][help] */
                           char *ref_tbl_name, char *ref_name, 
                           char * attr_value, char *condition)
{
static char query[STR_L];
SQ_result_set_t *sql_result;
SQ_row_t *sql_row;
char *sql_str;

 sprintf(query, "SELECT %s FROM %s "
                "WHERE %s='%s' ",
                field, ref_tbl_name, ref_name, attr_value);
 if (condition)strcat(query, condition);

//fprintf(stderr, "D:<get_field_str>:query: %s\n", query);
 sql_result=SQ_execute_query(SQ_STORE, tr->sql_connection, query);
 
 if(sql_result == NULL) {
    fprintf(stderr,"ERROR: %s\n", SQ_error(tr->sql_connection));
    return(NULL);
 }
        
         
 if ((sql_row = SQ_row_next(sql_result)) != NULL) {
        sql_str = SQ_get_column_string(sql_result, sql_row, 0);

     /* We must process all the rows of the result,*/
     /* otherwise we'll have them as part of the next qry */
        while ( (sql_row = SQ_row_next(sql_result)) != NULL) {
          fprintf(stderr, "E:<get_field_str> error : Dupl PK[%s]\n", query);
          if(sql_str)free(sql_str); sql_str=NULL;
        }
 }
 else sql_str=NULL;
 
 if(sql_result){ SQ_free_result(sql_result); sql_result=NULL; }
 return(sql_str);
}

/************************************************************
* long get_sequence_id(Transaction_t *tr)
* >0 - success
* -1 - sql error
*
* **********************************************************/

long get_sequence_id(Transaction_t *tr)
/* [<][>][^][v][top][bottom][index][help] */
{
char *sql_str;
char str_id[STR_M];
long sequence_id=-1;


  sprintf(str_id, "%ld", tr->object_id);
  sql_str= get_field_str(tr, "sequence_id", "last", "object_id", str_id, NULL);
  if(sql_str) {
          sequence_id = atol(sql_str);
//                fprintf(stderr, "D: Retrieved set serial id = %ld\n", sequence_id);
          free(sql_str);
  }
  
  return(sequence_id);

}


/************************************************************
* long get_ref_id(char *ref_tbl_name, char *ref_name, char * attr_value)
* >0 - success
* -1 - sql error
*
* **********************************************************/

static long get_ref_id(Transaction_t *tr, char *ref_tbl_name, char *ref_name, char * attr_value, char *condition)
/* [<][>][^][v][top][bottom][index][help] */
{
char *sql_str;
long ref_id=-1;

//fprintf(stderr, "D:<get_ref_id>: entering...\n");

        sql_str= get_field_str(tr, "object_id", ref_tbl_name, ref_name, attr_value, condition);
        if(sql_str) {
                 ref_id = atol(sql_str);
//               fprintf(stderr, "D: Retrieved set serial id = %ld\n", ref_id);
                 free(sql_str);
        }
        return(ref_id); 
}


static int isnichandle(char *name)
/* [<][>][^][v][top][bottom][index][help] */
{
 return(MA_isset(WK_new(name), WK_NIC_HDL));
}

static int sql_info(SQ_connection_t *sql_connection, int info[3])
/* [<][>][^][v][top][bottom][index][help] */
{
int ii;
char *colon, *buf_ptr, buf[20]; 
char *infoline;

//fprintf(stderr, "D: Getting additional information about query\n");
  infoline=mysql_info(sql_connection); 
//fprintf(stderr, "D: %s\n", infoline);  
  ii=0;
  colon = infoline;
  while (*colon != '\0') {
   colon++;
   buf_ptr=buf;
   if(isdigit((int)*colon)){
    while(isdigit((int)*colon)){
     *buf_ptr=*colon; buf_ptr++; colon++;
    }
    *buf_ptr='\0';
    info[ii]=atoi(buf); ii++;
   } 
  }
//  free(infoline);
//fprintf(stderr, "D: return %d\n", res[res_type]);  
return(0);
}


static char *get_set_name(C_Type_t class_type)
/* [<][>][^][v][top][bottom][index][help] */
{
 switch(class_type){
 case C_RT:     return("route_set");
 case C_AN:     return("as_set");
 default:       return(NULL);
 }
}


/************************************************************
* auth_member_of()                                          *
*                                                           *
* Function that checks the authorization for membership     *
* (i.e. if the object is authorized to be a memeber by      *
* mbrs-by-ref attribute of the set is refers by member-of   *
* attribute).                                               *
* First checks if 'mbrs-by-ref: ANY'                        *
* If not then checks that maintner referenced by            *
* mbrs-by-ref attribute of the set is the one in mnt-by.    *
*                                                           *
* Returns:                                                  *
* 0  success                                                *
* 1  not allowed                                            *
* -1 SQL error                                              *  
*                                                           *
*************************************************************/
static int auth_member_of(Attribute_t *attr, Transaction_t *tr)
/* [<][>][^][v][top][bottom][index][help] */
{
GString *query;
SQ_result_set_t *sql_result;
SQ_row_t *sql_row;
//char *sql_str;
char *set_name;
//long set_id;
//my_ulonglong num;
int error;


 error=0;
        
/* Check if set has mbrs_by_ref==ANY 
   In such case mbrs_by_ref.mnt_id==0 
*/

 if ((query = g_string_sized_new(STR_XL)) == NULL){
  tr->succeeded=0;
  tr->error |= ERROR_U_MEM; 
  fprintf(stderr, "E: cannot allocate gstring\n"); 
  return(-1); 
 }
 
 set_name= get_set_name(tr->class_type);
// fprintf(stderr, "D:<auth_member_of>: Got set name: %s\n", set_name); 
 g_string_sprintf(query,"SELECT %s.object_id FROM mbrs_by_ref, %s "
                        "WHERE mbrs_by_ref.object_id=%s.object_id "
                        "AND %s.%s='%s' AND mbrs_by_ref.mnt_id=0 ", 
                        set_name, set_name, set_name, set_name, set_name, attr->value);
// fprintf(stderr, "D:<auth_member_of>: query: %s\n", query->str);

 sql_result=SQ_execute_query(SQ_STORE, tr->sql_connection, query->str);
// if (sql_result ==NULL) { // ????????
//   fprintf(stderr, "E:<auth_member_of>: NULL SQL result[%s]\n", query->str);
//   g_string_free(query, TRUE);
//   return(1);
// }    

 if ((sql_result==NULL) || ((sql_row = SQ_row_next(sql_result))==NULL)){
    if(sql_result){ SQ_free_result(sql_result); sql_result=NULL; }

/* Check if our mnt_by belongs to mbrs_by_ref list of the set */
    g_string_sprintf(query, "SELECT mbrs_by_ref.object_id FROM route_set, mbrs_by_ref, mnt_by "
                            "WHERE mbrs_by_ref.mnt_id=mnt_by.mnt_id "
                            "AND mnt_by.object_id=%ld "
                            "AND %s.object_id=mbrs_by_ref.object_id "
                            "AND %s.%s='%s' "
                            "AND mnt_by.thread_id!=0 ",
                            tr->object_id, set_name, set_name, set_name, attr->value);

//      fprintf(stderr, "D:<auth_member_of>: query: %s\n", query->str);                                         
                                                        
    sql_result=SQ_execute_query(SQ_STORE, tr->sql_connection, query->str);

    if(sql_result == NULL) {
       fprintf(stderr,"ERROR: %s\n", SQ_error(tr->sql_connection));
       g_string_free(query, TRUE);
       return(-1);
    }

    if ((sql_row = SQ_row_next(sql_result)) == NULL) {
/* Membership is not authorized */
      fprintf(stderr, "E:<auth_member_of> : Membership is not autorized[%s]\n", query->str);
      if(sql_result){ SQ_free_result(sql_result); sql_result=NULL; }
      g_string_free(query, TRUE);
      return(1);
    }
 }
        
//      sql_str = SQ_get_column_string(sql_result, sql_row, 0);
/* We must process all the rows of the result, otherwise we'll have them as part of the next qry */
 while ( (sql_row = SQ_row_next(sql_result)) != NULL) {
   fprintf(stderr, "E:<auth_member_of> error : More than one object with the same PK\n");
   error=-1;
 }
 if(sql_result){ SQ_free_result(sql_result); sql_result=NULL; }
 g_string_free(query, TRUE);
 return(0);
}/* auth_member_of()  */
        

/************************************************************
* create_dummy()                                            *
*                                                           *
* Function that creates a dummy object (that is one that    *
* is referenced from an object but does not                 *
* exist in the database).                                   *
* Dummy object exists only in relevant main and 'last'      *
* tables. Its creation is controlled by tr->dummy_allowed.  *
* Queries for the dummies are defined in Dummy[] array.     *
*                                                           *
* Returns:                                                  *
* 0  success                                                *
* 1  no rf integrity and dummy not allowed
* -1 SQL error                                              *
*                                                           *
*************************************************************/
static int create_dummy(Attribute_t *attr, Transaction_t *tr) 
/* [<][>][^][v][top][bottom][index][help] */
{
SQ_result_set_t *sql_result;
char *query_fmt;
int num;
long dummy_id;
char query[STR_L];
//int result;
char *set_name;
char *p_name;
int query_type;
long timestamp;
char str_id[STR_M];
gchar *chopped_nh=NULL;
gchar *attr_value=NULL;


        query_fmt = Dummy[attr->type].qry;
        if (strcmp(query_fmt, "") == 0) { fprintf(stderr, "E:<create_dummy>: empty query string\n"); return(1); }
        if ((attr->type!=A_MO) &&  (tr->dummy != 1)) return(1);  

        /* insert dummy in the last table */
                sprintf(str_id, "%ld", tr->object_id);
                timestamp=time(NULL);
                sprintf(query, "INSERT INTO last SET thread_id=%d, timestamp=%ld, object_type=%d, object='DUMMY for %s'", 
                                                                tr->thread_ins, timestamp, DUMMY_TYPE, str_id);
// fprintf(stderr, "D: making dummy entry in the last table\n %s\n", query);
                sql_result=SQ_execute_query(SQ_STORE, tr->sql_connection, query);
                num = mysql_affected_rows(tr->sql_connection);
//              fprintf(stderr, "D: query: %d rows affected\n", num);
                if (sql_result)SQ_free_result(sql_result);  
                if ((num == -1) || (num == 0)) {
//fprintf(stderr, "E: dummy->last:[%s]\n", query);
                        return(-1);
                }       
        
        /* insert dummy in the main table */
        dummy_id=mysql_insert_id(tr->sql_connection); 
        tr->dummy_id[tr->ndummy]=dummy_id;
        tr->ndummy++; // increase number of attempts to create dummy
//      fprintf(stderr, "D:<create_dummy>:dummy_id=%ld\n", dummy_id);
        query_type=Dummy[attr->type].qtype;
        switch (query_type) {   
         case UD_AX_PR:
                        // chop nic-hdl if bigger that MAX_NIC_HDL
                        if(strlen(attr->value)>MAX_NIC_HDL){
                         chopped_nh = g_strndup(attr->value, MAX_NIC_HDL);
                         attr_value=chopped_nh;
                        } else attr_value = attr->value;
                        sprintf(query, query_fmt, tr->thread_ins, dummy_id, attr_value, DUMMY_TYPE);
                        if(chopped_nh){ free(chopped_nh); chopped_nh=NULL;}
                        break;
         case UD_AX_MT: 
                        sprintf(query, query_fmt, tr->thread_ins, dummy_id, attr->value, DUMMY_TYPE);
                        break;
                // as-set, route-set
         case UD_AX_MO: 
                        set_name = get_set_name(tr->class_type);
                        sprintf(query, query_fmt, set_name, tr->thread_ins, dummy_id, set_name, attr->value);     
                        break;
         default:
                        fprintf(stderr, "E: query not defined for this type of attribute[%d]\n", attr->type);
                        break;
        }
        
//fprintf(stderr, "D: query: %s\n", query);
        sql_result=SQ_execute_query(SQ_STORE, tr->sql_connection, query);
        num = mysql_affected_rows(tr->sql_connection);
//      fprintf(stderr, "D: query: %d rows affected\n", num);
        if (sql_result)SQ_free_result(sql_result);
        if ((num == -1) || (num == 0)) {
fprintf(stderr, "E: dummy->main:[num=%d][%s]\n", num, query);
                return(-1);
        }
        
        if( query_type == UD_AX_MO ){ // Create row in mbrs_by_ref
                sprintf(query, " INSERT mbrs_by_ref SET thread_id=%d, object_id=%ld, mnt_id=0, object_type=%d ", 
                                        tr->thread_ins,dummy_id, DUMMY_TYPE);
//              fprintf(stderr, "D: query: %s\n", query);
                sql_result=SQ_execute_query(SQ_STORE, tr->sql_connection, query);
                num = mysql_affected_rows(tr->sql_connection);
//              fprintf(stderr, "D: query: %d rows affected\n", num);
                if (sql_result)SQ_free_result(sql_result);
                if ((num == -1) || (num == 0)) {
                        fprintf(stderr, "E: dummy->main:[num=%d][%s]\n", num, query);
                        return(-1);
                }
        }
        else
        if( (query_type == UD_AX_PR) && (!isnichandle (attr->value)) ){ // Create rows in names
          // parse the names
//        fprintf(stderr,"adding names for dummy\n");
           query_fmt = Insert[A_PN].qry;
           attr_value = g_strdup(attr->value);
           while((p_name=s_split(attr_value))){
                sprintf(query, query_fmt, tr->thread_ins, dummy_id, DUMMY_TYPE, p_name);
//              fprintf(stderr, "D: query: %s\n", query);
                sql_result=SQ_execute_query(SQ_STORE, tr->sql_connection, query);
                num = mysql_affected_rows(tr->sql_connection);
//              fprintf(stderr, "D: query: %d rows affected\n", num);
                if (sql_result)SQ_free_result(sql_result);
           }
           free(attr_value);
        }
        
        return(0);
}

/************************************************************
* update_attr()                                             *
*                                                           *
* Function that updates an attribute if it already exists.  *
* Called from each_attribute_proces() function if it        *
* cannot insert the row.                                    *
* Queries for the attributes are defined in Update[] array. *
*                                                           *
* Returns: Nothing. Error code is stored in tr->succeeded.  *
*                                                           *
*************************************************************/
static int update_attr(Attribute_t *attr, Transaction_t *tr)
/* [<][>][^][v][top][bottom][index][help] */
{
SQ_result_set_t * sql_result;
int num;
char *query_fmt;
//GString *query;
char *set_name;
unsigned int if_address;
char * rf_host;
int rf_port, rf_type;
gchar *chopped_nh=NULL;
char *a_value;
//int dupl;
int sq_info[3];
char * condition;
char query[STR_L];

 if(tr->load_pass!=0) return(0);

//      fprintf(stderr, "D: updating attribute...\n");
   
   query_fmt = Update[attr->type].qry;
   if (strcmp(query_fmt, "") == 0) return(0);

   switch (Update[attr->type].qtype) {
         case UD_MAIN_: sprintf(query, query_fmt, tr->thread_upd, tr->object_id);
                        break;
         case UD_MA_PR: 
                        sprintf(query, query_fmt, tr->thread_upd, tr->class_type, tr->object_id);
                        break;  
         case UD_MA_LA: // save the new value for commit
                        //g_string_free(query, TRUE);
                        tr->save=attr->value;
                        return(0);
                        break;                  
         case UD_AX_PR:
                        a_value = attr->value;
                        if(strlen(attr->value)>MAX_NIC_HDL){ // This is for non-conformant admin-c, etc.
                         chopped_nh = g_strndup(attr->value, MAX_NIC_HDL);
                         a_value=chopped_nh;
                        }
                        if (tr->dummy!=1)condition="AND dummy=0 "; else condition=NULL;
                        sprintf(query, query_fmt, tr->thread_upd, tr->object_id, 
                                get_ref_id(tr, "person_role", "nic_hdl", a_value, condition));
                        if(chopped_nh) free(chopped_nh);
                        break;
         case UD_AX_MT: 
                        if (tr->dummy!=1)condition="AND dummy=0 "; else condition=NULL;
                        sprintf(query, query_fmt, tr->thread_upd, tr->object_id, 
                                get_ref_id(tr, "mntner", "mntner", attr->value, condition));
                        break;
         case UD_AX_MO: 
                        set_name = get_set_name(tr->class_type);
//                    fprintf(stderr, "D: retrieved set name: %s\n", set_name);
                        if (tr->dummy!=1)condition="AND dummy=0 "; else condition=NULL;
                        sprintf(query, query_fmt, tr->thread_upd, tr->object_id, 
                                        get_ref_id(tr, set_name, set_name, attr->value, condition));
                        break;                          
         case UD_AX_MR:
                        if ((strcmp(attr->value, "ANY")==0) || (strcmp(attr->value, "any")==0) || (strcmp(attr->value, "Any")==0))
                        sprintf(query, query_fmt, tr->thread_upd, tr->object_id, 
                                get_ref_id(tr, "mntner", "mntner", "ANY",NULL));
                        else {  
                         if (tr->dummy!=1)condition="AND dummy=0 "; else condition=NULL;
                         sprintf(query, query_fmt, tr->thread_upd, tr->object_id, 
                                get_ref_id(tr, "mntner", "mntner", attr->value, condition));
                        }
                        break;
         case UD_LEAF_: 
                        sprintf(query, query_fmt, tr->thread_upd, tr->object_id, attr->value);
                        break;
         case UD_LF_IF:
                // Convert ascii ip -> numeric one. Later to save in tr->save while processing INSERT
                        convert_if(attr->value, &if_address);
                        sprintf(query, query_fmt, tr->thread_upd, tr->object_id, if_address);
                        break;
         case UD_LF_RF:
                        rf_host=convert_rf(attr->value, &rf_type, &rf_port);
                        sprintf(query, query_fmt, tr->thread_upd, tr->object_id, rf_type, rf_host, rf_port);
                        if(rf_host)free(rf_host);
                        break;                  
         case UD_LF_AY:
                        sprintf(query, query_fmt, tr->thread_upd, tr->object_id, convert_time(attr->value));
                        break;          
           default:
                fprintf(stderr, "E:<e_a_u> query not defined for this type of attribute:[%d]\n", attr->type);
                        tr->error|=ERROR_U_BUG;
                        tr->succeeded=0;
                        g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:no update qry\n" ,ERROR_U_BUG, attr->type, attr->value);
                        break;
        }
//fprintf(stderr, "D: update: [%s]", query);

    sql_result=SQ_execute_query(SQ_STORE, tr->sql_connection, query);
    num = mysql_affected_rows(tr->sql_connection);
//  fprintf(stderr, "D: query: %d rows affected\n", num);
      if ((num == -1)) {
        fprintf(stderr, "E:<each_attribute_create> update query:[%d][%s]\n", num, query);
        tr->error|=ERROR_U_DBS;
        tr->succeeded=0;
        g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:update qry\n" ,ERROR_U_DBS, attr->type, attr->value);
      }
      else
      if(num == 0) { // check for duplicates
                sql_info(tr->sql_connection, sq_info); // REPLACE ... SELECT
                if ((sq_info[SQL_DUPLICATES]==0) && (sq_info[SQL_MATCHES]==0)) { // this is because of dummies
        fprintf(stderr, "E: Update: empty query result: [%s]\n", query);
        tr->error|=ERROR_U_DBS;
        tr->succeeded=0;
        g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:null update qry res\n" ,ERROR_U_DBS, attr->type, attr->value);
                } // else duplicate entry - silently drop it  
      } 
  if (sql_result){ SQ_free_result(sql_result);sql_result=NULL; }
  if (attr->type == A_MO){
//              fprintf(stderr, "D:<e_a_p>: need to auth membership\n");
                if(auth_member_of(attr, tr)!=0){
                 tr->error|=ERROR_U_AUT;
                 tr->succeeded=0;
                 fprintf(stderr, "E:<each_attribute_create>: membership not allowed\n");
                 g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:membership not allowed\n" ,ERROR_U_AUT, attr->type, attr->value);     
                }
  }
//fprintf(stderr, "D:<update_attr>: returning   \n");   
return(0);
}/*  update_attr()  */


/************************************************************
* each_attribute_proces()                                   *
*                                                           *
* Main function that processes object attributes one by one.*
* Called from g_slist_foreach() function.                   * 
* First it tries to insert an attribute.                    *
* If an error it assumes that attribute is already in       *
* a table and calls update_attr() to update it.             *
* Queries for the attributes are defined in Insert[] array. * 
*                                                           *
* Returns: Nothing. Error code is stored in tr->succeeded.  *
*                                                           *
*************************************************************/
static void each_attribute_process(void *element_data, void *tr_ptr) 
/* [<][>][^][v][top][bottom][index][help] */
{
SQ_result_set_t * sql_result;
//my_ulonglong num;
int num;
char *query_fmt;
int query_type;
//int dupl;
int do_query;
Attribute_t *attr = element_data;
Transaction_t *tr = (Transaction_t *)tr_ptr;
unsigned int prefix, prefix_length;
unsigned int begin_in, end_in;
int begin_as, end_as;
//GString *query_u;
char query[STR_L];
char * set_name;
char * rf_host; // needs to be deleted after use
int rf_type, rf_port;
gchar *chopped_nh=NULL;
char *a_value;
int sq_info[3];
char *mu_mntner, *mu_prefix;
int dummy_err;

static rx_bin_data_t rx_bin_data;
static rx_inum_data_t rx_inum_data;


  if(tr->succeeded == 0) return; // no sense to continue
  
  do_query=1;
  
  query_type=Insert[attr->type].qtype;

/* For loadind pass #1 we need to process only main tables */
  if(tr->load_pass==1){ 
        switch(query_type) {
         case UD_MAIN_:
         case UD_MA_U2:
         case UD_MA_PR:
         case UD_MA_RT:
         case UD_MA_IN:
         case UD_MA_I6:
         case UD_MA_LA:
         case UD_MA_AK:
                        break;
         default:       return; // return for other than MAIN tables
        }
  }
  
  query_fmt = Insert[attr->type].qry;

  if (strcmp(query_fmt, "") == 0) return;
// fprintf(stderr,"[%d]:[%s]\n", attr->type, attr->value);  
  query_type=Insert[attr->type].qtype;
  switch (query_type) {
   case UD_MAIN_: 
                if (tr->action==TR_UPDATE) do_query=0;
                else
                sprintf(query, query_fmt, tr->thread_ins, tr->object_id, attr->value);
                break;
   case UD_MA_U2: 
                if (tr->action==TR_UPDATE) do_query=0;
                else
                sprintf(query, query_fmt, tr->thread_ins, attr->value, tr->object_id);
                if(attr->type == A_OR) {
                        save_rx_orig(&rx_bin_data, attr->value);
                        tr->save = (void *)&rx_bin_data; // just in case
                }       
                break;
   case UD_MA_PR: 
                if (tr->action==TR_UPDATE) do_query=0;
                else
                sprintf(query, query_fmt, tr->thread_ins, tr->class_type, tr->object_id,  attr->value);
                break;  
   case UD_MA_RT:
                if (tr->action==TR_UPDATE) do_query=0;
                else {
                  expand_rt(attr->value, &prefix, &prefix_length);
                //fprintf(stderr, "D: route: %u/%u\n", prefix, prefix_length);                  
                sprintf(query, query_fmt, tr->thread_ins,  
                        tr->object_id, prefix, prefix_length);
                // save stuff for radix update
                  save_rx_pref(&rx_bin_data, prefix, prefix_length);
                  tr->save = (void *)&rx_bin_data;
                }
                break;
   case UD_MA_IN:
                if (tr->action==TR_UPDATE) do_query=0;
                else {
                  convert_in(attr->value, &begin_in, &end_in);
                  sprintf(query, query_fmt, tr->thread_ins, tr->object_id, begin_in, end_in);
                  save_rx_rang(&rx_inum_data, begin_in, end_in);
                  tr->save = (void *)&rx_inum_data;
                }       
                break;
   case UD_MA_I6:
                break;  
   case UD_MA_LA: // save the new value for commit
                tr->save=attr->value;
//              fprintf(stderr, "D:<e_a_p> attribute saved: %s\n", tr->save);
                return;
                break;
   case UD_MA_AK:
                if (tr->action==TR_UPDATE) do_query=0;
                else {
                  convert_as_range(attr->value, &begin_as, &end_as);
                  sprintf(query, query_fmt, tr->thread_ins, tr->object_id, begin_as, end_as);
                }
                break;                          
   case UD_AUX__: 
                a_value = attr->value;
                if((attr->type==A_AC) || (attr->type==A_TC) || (attr->type==A_ZC))
                 if(strlen(attr->value)>MAX_NIC_HDL){
                        chopped_nh = g_strndup(attr->value, MAX_NIC_HDL);
                        a_value=chopped_nh;
                 } 
                sprintf(query, query_fmt, tr->thread_ins, tr->object_id, tr->class_type, a_value);
                if(tr->dummy!=1)strcat(query, " AND dummy=0 ");
                if(chopped_nh){ free(chopped_nh); chopped_nh=NULL;}
                break;
   case UD_AX_MO:
                set_name = get_set_name(tr->class_type);
//              fprintf(stderr, "D: retrieved set name: %s\n", set_name);
                sprintf(query, query_fmt, tr->thread_ins,  
                 tr->object_id, set_name, tr->class_type, set_name, set_name, set_name, attr->value);
                break;  
   case UD_AX_MR:
                if ((strcmp(attr->value, "ANY")==0) || (strcmp(attr->value, "any")==0) || (strcmp(attr->value, "Any")==0))
                 sprintf(query, query_fmt, tr->thread_ins, tr->object_id, tr->class_type, "ANY");
                else  
                 sprintf(query, query_fmt, tr->thread_ins, tr->object_id, tr->class_type, attr->value);
                break;  
   case UD_AX_MU:
                a_value=g_strdup(attr->value);
                mu_mntner=s_splitn(a_value, 1);
                mu_prefix=s_splitn(a_value, 1);
                sprintf(query, query_fmt, tr->thread_ins, tr->object_id, mu_prefix, tr->class_type, mu_mntner);
                free(a_value);
                if(tr->dummy!=1)strcat(query, " AND dummy=0 ");
                break;
   case UD_LEAF_: 
                sprintf(query, query_fmt, tr->thread_ins, tr->object_id, attr->value);
                break;
   case UD_LF_OT:
                sprintf(query, query_fmt, tr->thread_ins, tr->object_id, tr->class_type, attr->value);
                break;                          
   case UD_LF_AT: // check PGPKEY. If yes - check the existence of key-cert.
                if(tr->dummy!=1){
                 if(strncmp("PGPKEY", attr->value, 6)==0) {
                        if(get_ref_id(tr, "key_cert", "key_cert", attr->value, NULL)<=0) { 
                                fprintf(stderr, "E:<e_a_p>: No key-cert object.\n");
                                tr->error|=ERROR_U_OBJ;
                                tr->succeeded=0;
                                g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:no key-cert object\n" ,ERROR_U_OBJ, attr->type, attr->value);
                                return;
                        }
                 }
                } 
                sprintf(query, query_fmt, tr->thread_ins, tr->object_id, tr->class_type, attr->value);
                break;      
   case UD_LF_IF:
                // Convert ascii ip -> numeric one
                convert_if(attr->value, &prefix);
                sprintf(query, query_fmt, tr->thread_ins, tr->object_id, prefix);
                break;
   case UD_LF_RF:
                rf_host=convert_rf(attr->value, &rf_type, &rf_port);
                sprintf(query, query_fmt, tr->thread_ins, 0 /*tr->object_id*/ , rf_type, rf_host, rf_port);
                if(rf_host)free(rf_host);
                break;  
   case UD_LF_AY:
                sprintf(query, query_fmt, tr->thread_ins, tr->object_id, convert_time(attr->value));
                break;
        default:
fprintf(stderr, "E: query not defined for this type of attribute\n");
                break;
  }
  
//fprintf(stderr, "D: insert: [%s]", query);

  if(do_query){
   sql_result=SQ_execute_query(SQ_STORE, tr->sql_connection, query);
   num = mysql_affected_rows(tr->sql_connection);
   if (sql_result)SQ_free_result(sql_result);sql_result=NULL;    
  } 
  else {
   update_attr(attr, tr);
   return;
  }
  
//  fprintf(stderr, "D: query: %d rows affected\n", num);

  if(num>0){ // this is OK
// if attr=="member_of" we need additional processing
        if (attr->type == A_MO){
//              fprintf(stderr, "D:<e_a_p>: need to auth membership\n");
                if(auth_member_of(attr, tr)!=0){
                 tr->error|=ERROR_U_AUT;
                 tr->succeeded=0;
                 fprintf(stderr, "E:<each_attribute_create>: membership not allowed\n");
                 g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:membership not allowed\n" ,ERROR_U_AUT, attr->type, attr->value);     
                }
        }
        return;
  }

  if(num == -1){ // if not update that is the  error condition. free resources and return (except some attributes)
        if (tr->action==TR_UPDATE) {
                update_attr(attr, tr);
                return;
        }       
        else { 
                switch(attr->type) {
                case A_EM: break; // duplicate e-mail:
                case A_PN: break; // fe: Antony Antony
                case A_RO: break; // fe: IB og Co Reklame og Marketing
                
                default:
 // !!!!!!!! tr->succeeded=0; fprintf(stderr, "E: query returned an error: [%s]\n", query->str);
                        break;
                }
        }
  }
  else
  if(num == 0) { 
        sql_info(tr->sql_connection, sq_info);
        if (sq_info[SQL_DUPLICATES]>0) { // update attribute
                if (sq_info[SQL_DUPLICATES]>1) { // this is an error - more that 1 duplicate
                        fprintf(stderr, "E: Update: Too many duplicates for query: [%s]\n", query);
                        tr->error|=ERROR_U_DBS;
                        tr->succeeded=0;
                        g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:duplicates\n" ,ERROR_U_DBS, attr->type, attr->value);
                        return;
                }
                update_attr(attr, tr);
        }
        else { // try to create dummy and repeat query
                
//              fprintf(stderr, "W: no ref. integrity. Trying to create dummy...");

                dummy_err = create_dummy(attr, tr);
                if (dummy_err == 0) {
//                      fprintf(stderr, "D: ... dummy OK\n");
                        g_string_sprintfa(tr->error_script,"W[%d][%d:%s]:dummy created\n" ,0, attr->type, attr->value);
//                      fprintf(stderr, "D: repeating query: %s\n", query);
                        sql_result=SQ_execute_query(SQ_STORE, tr->sql_connection, query);
                        num = mysql_affected_rows(tr->sql_connection);
                        if (sql_result) { SQ_free_result(sql_result); sql_result=NULL;}
                        if ((num == -1) || (num==0)) {
                          tr->error|=ERROR_U_DBS;
                          tr->succeeded=0;
                          fprintf(stderr, "E:<each_attribute_create>: insert query: [%s]\n", query);
                          g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:insert qry\n" ,ERROR_U_DBS, attr->type, attr->value);
                        }
                }
                else 
                 if(dummy_err == 1) {
                   tr->error |= ERROR_U_OBJ;
                   tr->succeeded=0;
                   g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:rf failure\n" ,ERROR_U_OBJ, attr->type, attr->value);
                 }
                 else {
                   tr->error|=ERROR_U_DBS;
                   tr->succeeded=0;
                   fprintf(stderr, "E:<each_attribute_create>: dummy not created\n");
                   g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:dummy not created\n" ,ERROR_U_DBS, attr->type, attr->value);
                }       
        }// RI
  }// if num == 0
  return;
} /* each_attribute_process() */



/************************************************************
* each_primary_key_select()                                 *
*                                                           *
* Function that forms a query for an object (w prinary keys)*
* Called from g_slist_foreach() function.                   *
* Primary keys are defined in Select[] array.               *
*                                                           *
* Returns: Nothing. Error code is stored in tr->succeeded.  *
*                                                           *
*************************************************************/ 
static void each_primary_key_select(void *element_data, void *result_ptr) 
/* [<][>][^][v][top][bottom][index][help] */
{
Attribute_t *attr = element_data;
GString *result = (GString *)result_ptr;
char *query_fmt;
unsigned int prefix, prefix_length;
unsigned int begin_in, end_in;
int begin_as, end_as;
  
  query_fmt = Select[attr->type].qry;

// fprintf(stderr, "D: qry fmt: %s\n", query_fmt);

  if (strcmp(query_fmt, "") != 0) {
    switch (Select[attr->type].qtype) {
     case UD_MAIN_: 
                g_string_sprintfa(result, query_fmt, attr->value);
                break;
     case UD_MA_RT:
                expand_rt(attr->value, &prefix, &prefix_length);
                g_string_sprintfa(result, query_fmt, prefix, prefix_length);
                break;
     case UD_MA_IN:
                convert_in(attr->value, &begin_in, &end_in);
                g_string_sprintfa(result, query_fmt, begin_in, end_in);
                break;
     case UD_MA_AK:
                convert_as_range(attr->value, &begin_as, &end_as);
                g_string_sprintfa(result, query_fmt, begin_as, end_as);
                break;
     default:
fprintf(stderr, "E:<e_p_k_s>: query not defined for this type of attribute:[%d]\n", attr->type);


        break;
    } 
//fprintf(stderr, "D: each_primary_key_select(): %s\n",result->str);    
  }
} 

/************************************************************
* perform_create(const Object_t *obj, Transaction_t *tr)    * 
*                                                           *
* Procedure for creating a new object.                      *
* First inserts object into 'last' table and gets object_id.*
* Then processes all attributes.                            *
*                                                           *
* Returns: Nothing. Error code is stored in tr->succeeded.  *
*                                                           *
*************************************************************/ 
static int perform_create(Transaction_t *tr) 
/* [<][>][^][v][top][bottom][index][help] */
{
 Object_t *obj=tr->object;
 SQ_result_set_t *sql_result;
 char *str;
 static char query[STR_XXXL];
 int  num;
 long timestamp;
  
      str = (obj->object)->str;
      timestamp=time(NULL);
      sprintf(query, "INSERT INTO last SET thread_id=%d, timestamp=%ld, object_type=%d, object='%s' ",
                     tr->thread_ins, timestamp, tr->class_type, str);

      sql_result=SQ_execute_query(SQ_STORE, tr->sql_connection, query);
      num = mysql_affected_rows(tr->sql_connection);
      if (sql_result)SQ_free_result(sql_result);
      if ((num == -1) || (num == 0)) {
        fprintf(stderr, "E ERROR!<perform_create>: INSERT last failed:%d\n", num);
        tr->error|=ERROR_U_DBS;
        tr->succeeded=0;
        g_string_sprintfa(tr->error_script,"E[%d][:]:INSERT last failed\n" ,ERROR_U_DBS);
      }
      else {
        tr->object_id=mysql_insert_id(tr->sql_connection);
        g_slist_foreach(obj->attributes, each_attribute_process, tr);
      }
    return(0);  
} /* perform_create() */

/************************************************************
* perform_update(Transaction_t *tr)                         * 
*                                                           *
* Procedure for updating (existing) object.                 *
* First processes all attributes.                           *
* Then saves previous object in 'history' and updates       *
* 'last' table.                                             *
*                                                           *
* Returns: Nothing. Error code is stored in tr->succeeded.  *
*                                                           *
*************************************************************/ 
static int perform_update(Transaction_t *tr) 
/* [<][>][^][v][top][bottom][index][help] */
{
Object_t *obj=tr->object;
SQ_result_set_t * sql_result;
char *str;
char str_id[STR_M];
char *sql_str;
static char query[STR_XXXL];
int num;
long sequence_id;
long timestamp;

  /* process each attribute one by one */
  g_slist_foreach(obj->attributes, each_attribute_process, tr);

  /* If we've already failed or this is fast load - just return */
  if((tr->succeeded == 0) || (tr->load_pass != 0)) return(0);
  
    /* No return: thread_id=0 */
    /* Do it only if previous transactions finished well */
       
    /* copy object to the history table */
fprintf(stderr, "INSERT history\n");    
    sprintf(query,"INSERT history "
                  "SELECT 0, object_id, sequence_id, timestamp, object_type, object "
                  "FROM last "
                  "WHERE object_id=%ld ", tr->object_id);

    sql_result=SQ_execute_query(SQ_STORE, tr->sql_connection, query);
    num = mysql_affected_rows(tr->sql_connection);
    if (sql_result)SQ_free_result(sql_result);
    if ((num == -1) || (num == 0)) {
         fprintf(stderr, "E ERROR!<perform_update>: INSERT history failed:[%d][%s]\n", num, query);
         tr->error|=ERROR_U_DBS;
         tr->succeeded=0;
         g_string_sprintfa(tr->error_script,"E[%d][:]:INSERT history failed\n" ,ERROR_U_DBS);
         return(-1);
    }

    /* get sequence number */
//fprintf(stderr, "get seq\n");    
    sprintf(str_id, "%ld", tr->object_id);
    sql_str= get_field_str(tr, "sequence_id", "last", "object_id", str_id, NULL);
    if(sql_str) {
          sequence_id = atol(sql_str);
          free(sql_str);
    }
    else {
         fprintf(stderr, "E ERROR!<perform_update> cannot get sequence_id: %d\n", num);
         tr->error|=ERROR_U_DBS;
         tr->succeeded=0;
         g_string_sprintfa(tr->error_script,"E[%d][:]:cannot get seq ID\n" ,ERROR_U_DBS);
         return(-1);
    }
   
    tr->sequence_id=sequence_id; // save it for rollback
        
       
    /* insert new version into the last */
    str = (obj->object)->str;
    timestamp=time(NULL);
    sequence_id++;
       
//fprintf(stderr, "UPDATE last\n");       
    /* If we are here - it's almost commit. Otherwise this row will not be updated at all. */
    sprintf(query, "UPDATE last "
                   "SET thread_id=0, sequence_id=%ld, timestamp=%ld, object_type=%d, object='%s' "
                   "WHERE object_id=%ld ",
                   sequence_id, timestamp, tr->class_type, str, tr->object_id);

    sql_result=SQ_execute_query(SQ_STORE, tr->sql_connection, query);
    num = mysql_affected_rows(tr->sql_connection);
    if (sql_result)SQ_free_result(sql_result);
    if ((num == -1) || (num == 0)) {
         fprintf(stderr, "E ERROR!<perform_update>: INSERT last failed: [%d][%s]\n", num, query);
         tr->error|=ERROR_U_DBS;
         tr->succeeded=0;
         g_string_sprintfa(tr->error_script,"E[%d][:]:INSERT last failed\n" ,ERROR_U_DBS);
         return(-1);
    }
 return(0);   
} /* perform_update() */




/************************************************************
* int object_process(Transaction_t *tr)                     *
*                                                           *
* This is the interface between core and upper layer        *
* All it gets is Transaction *tr, which contains all        *
* necessary information, including the object in its        *
* internal representation.                                  *
*                                                           *
* Returns: Nothing. Error code is stored in tr->succeeded.  *
*                                                           *
*************************************************************/ 
int object_process(Transaction_t *tr) 
/* [<][>][^][v][top][bottom][index][help] */
{
        
/* not supported */
 if(tr->class_type==C_I6) { 
   tr->succeeded=0; tr->error |= ERROR_U_NSUP;
   fprintf(stderr, "Object type currently not supported\n");
   return(-1);
 }  
        
        switch(tr->action){
         case TR_DELETE:
                fprintf(stderr, "D: Action: Delete...");
                printf("\tD: Action: Delete...");
                delete(tr);
                return(0); //commit is not needed
                break;
                
         case TR_UPDATE:
                fprintf(stderr, "D: Action: Update...");
                printf("\tD: Action: Update...");
                perform_update(tr);
                break;
                
         case TR_CREATE:
                fprintf(stderr, "D: Action: Create...");
                printf("\tD: Action: Create...");
                perform_create(tr);
                break;
                
         default:
                fprintf(stderr, "D: Action: Unknown...");
                tr->succeeded=0;
                tr->error|=ERROR_U_BADOP;
                return(-1);
                break;
        } 
   if(tr->load_pass == 0) { // not for fast loader
      if (tr->succeeded == 1) {
//fprintf(stderr, "D: Commit transaction...\n");      
        commit(tr);
        return(0);
      }
      else {
//fprintf(stderr, "D: Roll back transaction...\n");      
        rollback(tr);
        return(0);
      }
    }  
 return(0);   
} /* object_process() */


/* [<][>][^][v][top][bottom][index][help] */