modules/ud/ud_core.c

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

FUNCTIONS

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

   1 /***************************************
   2   
   3   $Revision: 1.35 $
   4 
   5   Core functions for update lower layer 
   6 
   7   Status: NOT REVUED, NOT TESTED
   8 
   9  Author(s):       Chris Ottrey, Andrei Robachevsky
  10 
  11   ******************/ /******************
  12   Modification History:
  13         andrei (17/01/2000) Created.
  14   ******************/ /******************
  15   Copyright (c) 2000                              RIPE NCC
  16  
  17   All Rights Reserved
  18   
  19   Permission to use, copy, modify, and distribute this software and its
  20   documentation for any purpose and without fee is hereby granted,
  21   provided that the above copyright notice appear in all copies and that
  22   both that copyright notice and this permission notice appear in
  23   supporting documentation, and that the name of the author not be
  24   used in advertising or publicity pertaining to distribution of the
  25   software without specific, written prior permission.
  26   
  27   THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  28   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
  29   AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
  30   DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
  31   AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  32   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  33  ***************************************/
  34 #include "ud.h"
  35 #include "ud_int.h"
  36 #include "ud_tr.h"
  37 
  38 #include <sys/types.h>
  39 #include <signal.h>
  40 #include <time.h>
  41 
  42 static int perform_update(Transaction_t *tr);
  43 
  44 static int perform_create(Transaction_t *tr);
  45 
  46 static void each_primary_key_select(void *element_data, void *result_ptr);
  47 
  48 static void each_attribute_process(void *element_data, void *tr_ptr);
  49 
  50 static void update_attr(Attribute_t *attr, Transaction_t *tr);
  51 
  52 static int create_dummy(Attribute_t *attr, Transaction_t *tr);
  53 
  54 static int auth_member_of(Attribute_t *attr, Transaction_t *tr);
  55 
  56 /***************************************************
  57 * char *s_split(char *line)                        *
  58 *                                                  *
  59 * Consequently returns words of the 'line'         * 
  60 * When there are no words it returns NULL          *
  61 * You need to retreive all words !                 *
  62 *                                                  *
  63 * NB This function damages 'line' replacing        *
  64 * whitespace with '\0'                             *
  65 * *************************************************/
  66 #define ATTR_DELIMITERS " ,"
  67 
  68 
  69 /**********************************************************
  70 * Attribute expansion/conversion functions                *
  71 ***********************************************************/
  72 /* Convert ifaddr attribute into numbers */
  73 er_ret_t convert_if(char *avalue, unsigned int *pif_address)
     /* [<][>][^][v][top][bottom][index][help] */
  74 {
  75 char *delim;
  76 ip_addr_t ip_addr;
  77 er_ret_t ret;
  78 
  79   if ((delim=index(avalue, ' '))!=NULL) *delim='\0';
  80   ret=IP_addr_a2v4(avalue, &ip_addr,  pif_address );
  81   return(ret);
  82 }
  83 
  84 
  85 /* Convert refer attribute. Free host after use ! */
  86 char *convert_rf(char *avalue, int *type, int *port)
     /* [<][>][^][v][top][bottom][index][help] */
  87 {
  88 char *delim, *token;
  89 char buff[STR_M];
  90 char *host;
  91 
  92   host=NULL;
  93   strcpy(buff, avalue);
  94   g_strchug(buff);
  95   delim=index(buff, ' ');
  96   *delim='\0';
  97   delim++; 
  98 
  99 /* convert the type      */
 100   if(strcmp(buff, S_RIPE)==0)*type=RF_RIPE;
 101    else if(strcmp(buff, S_INTERNIC)==0)*type=RF_INTERNIC;
 102     else if(strcmp(buff, S_SIMPLE)==0)*type=RF_SIMPLE;
 103      else if(strcmp(buff, S_CLIENTADDERSS)==0)*type=RF_CLIENTADDRESS;
 104 
 105   token=delim;
 106   g_strchug(token);
 107   delim=index(token, ' ');
 108   if(delim){
 109    *delim='\0';
 110    delim++; 
 111   }           
 112 /* convert the hostname      */
 113   host = g_strdup(token);
 114       
 115 /* convert port number      */
 116   if(delim){
 117     token=delim;        
 118     *port = atoi(token);
 119     if (*port==0) *port=RF_DEF_PORT; /* default port number*/
 120   } else *port=RF_DEF_PORT;
 121   return(host);
 122 }
 123 
 124 
 125 /* Convert AS# into integer */
 126 static int convert_as(char *as)
     /* [<][>][^][v][top][bottom][index][help] */
 127 {
 128 char *ptr;
 129  ptr=as; ptr++; ptr++; 
 130  return(atoi(ptr));   
 131 }
 132 
 133 /* Convert AS range (AS4321 - AS5672) into numbers */
 134 int convert_as_range(const char *as_range, int *begin, int *end)
     /* [<][>][^][v][top][bottom][index][help] */
 135 {
 136 char *range;
 137 char *token;
 138   
 139   range=g_strdup(as_range);
 140   token=range;
 141   *begin=convert_as(strsep(&token, " -"));
 142   *end=convert_as(strsep(&token, " -"));
 143   free(range);
 144   return(0);
 145 }
 146 
 147 /* Convert time in ASCII format (19991224) into time_t unix time */
 148 time_t convert_time(char *asc_time)
     /* [<][>][^][v][top][bottom][index][help] */
 149 {
 150 struct tm tm;
 151 char buf[STR_S];
 152 char *ptr;
 153 
 154   
 155   bzero(&tm, sizeof(tm));
 156   
 157   strncpy(buf, asc_time, 4); ptr=buf+4; *ptr='\0';
 158   tm.tm_year = atoi(buf) - 1900;
 159   
 160   strncpy(buf, (asc_time+4), 2); ptr=buf+2; *ptr='\0';
 161   tm.tm_mon = atoi(buf) - 1;
 162   
 163   strncpy(buf, (asc_time+6), 2); ptr=buf+2; *ptr='\0';
 164   tm.tm_mday = atoi(buf);
 165   
 166   return(mktime(&tm));
 167 
 168 }     
 169 
 170 
 171 /************************************************************
 172 *  char *get_set_name()                                     *
 173 *                                                           *
 174 * Returns set name for the specified object class           *
 175 *                                                           *
 176 * **********************************************************/
 177 static char *get_set_name(C_Type_t class_type)
     /* [<][>][^][v][top][bottom][index][help] */
 178 {
 179  switch(class_type){
 180   case C_RT:   return("route_set");
 181   case C_AN:   return("as_set");
 182   case C_IR:   return("rtr_set");
 183   default:     return(NULL);
 184  }
 185 }
 186 
 187 
 188 /************************************************************
 189 * long get_object_id()                                      *
 190 * Queries the database for an object.                       *
 191 * For constructing a query uses each_primary_key_select()   *
 192 *                                                           *
 193 * Returns:                                                  *
 194 * >0 - object exists, returns object_id                     *
 195 * 0  - object does not exist                                *
 196 * -1 - error (f.e. more than one object with the same PK)   *
 197 * Error code is stored in tr->error                         *
 198 *                                                           *
 199 * **********************************************************/
 200 long get_object_id(Transaction_t *tr)
     /* [<][>][^][v][top][bottom][index][help] */
 201 {
 202 Object_t *obj;
 203 SQ_result_set_t *sql_result;
 204 SQ_row_t *sql_row;
 205 char *sql_str;
 206 long object_id=0;
 207 int sql_err;
 208 
 209  obj=tr->object;
 210 
 211  if ((tr->query = g_string_sized_new(STR_XL)) == NULL){ 
 212   ER_perror(FAC_UD, UD_MEM, "cannot allocate gstring\n");
 213   tr->succeeded=0;
 214   tr->error |= ERROR_U_MEM;
 215   die; 
 216  }
 217  
 218 /* compose query */
 219  g_string_sprintf(tr->query, "SELECT object_id FROM %s WHERE",DF_get_class_sql_table(obj->type));
 220  /* add all primary keys */ 
 221  g_slist_foreach(obj->attributes, each_primary_key_select, tr);
 222  /* truncate the last ' AND '*/
 223  g_string_truncate(tr->query, (tr->query->len) - 4); 
 224         
 225 /* execute query */
 226  ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s [%s]", UD_TAG, tr->query->str);
 227  sql_err=SQ_execute_query(tr->sql_connection, tr->query->str, &sql_result);
 228   
 229 /* in case of an error copy error code and return */ 
 230  if(sql_err) {
 231    ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), tr->query->str);
 232    tr->succeeded=0;
 233    tr->error |= ERROR_U_DBS;
 234    die;
 235  }
 236  g_string_free(tr->query, TRUE);
 237 
 238 /* Fetch the row */ 
 239  if ((sql_row = SQ_row_next(sql_result)) != NULL) {
 240 /* Object exists */
 241 #define OBJECT_ID 0
 242    sql_str = SQ_get_column_string(sql_result, sql_row, OBJECT_ID);
 243    if (sql_str != NULL) {
 244      object_id = atol(sql_str);
 245      free(sql_str);
 246    }
 247 
 248 /* We must process all the rows of the result */
 249 /* otherwise we'll have them as part of the next qry */      
 250    while ( (sql_row = SQ_row_next(sql_result)) != NULL) object_id=-1;
 251  } else 
 252       object_id=0;  /* object does not exist*/
 253    
 254  SQ_free_result(sql_result);
 255  return(object_id);
 256 }
 257 
 258 /************************************************************
 259 * get_minmax_id()                                           *
 260 *                                                           *
 261 * Returns the min or max ID of the table                    *
 262 *                                                           *
 263 * Returns:                                                  *
 264 *  min (max=0) or max (max=1) ID                            *
 265 *  -1 in case of an error                                   *
 266 *                                                           *
 267 *                                                           *
 268 *************************************************************/
 269 long get_minmax_id(SQ_connection_t *sql_connection, char *id_name, char *tbl_name, int max)
     /* [<][>][^][v][top][bottom][index][help] */
 270 {
 271 char query[STR_M];
 272 SQ_result_set_t *sql_result;
 273 SQ_row_t *sql_row;
 274 char *sql_str;
 275 long id;
 276 char *minmax;
 277 int sql_err;
 278 
 279 if(max==1)minmax="max"; else minmax="min";
 280 
 281  sprintf(query, "SELECT %s(%s) FROM %s ", minmax, id_name, tbl_name);
 282 
 283  ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s [%s]", UD_TAG, query);
 284  sql_err = SQ_execute_query(sql_connection, query, &sql_result);
 285  
 286  if(sql_err) {
 287     ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(sql_connection), query);
 288     die;
 289  }
 290         
 291          
 292  if ((sql_row = SQ_row_next(sql_result)) != NULL) {
 293         sql_str = SQ_get_column_string(sql_result, sql_row, 0);
 294 
 295      /* We must process all the rows of the result,*/
 296      /* otherwise we'll have them as part of the next qry */
 297         while ( (sql_row = SQ_row_next(sql_result)) != NULL) {
 298           ER_perror(FAC_UD, UD_SQL, "duplicate PK [%s]\n", query);
 299           if(sql_str)free(sql_str); sql_str=NULL;
 300           die;
 301         }
 302  }
 303  else sql_str=NULL;
 304  
 305  if(sql_result){ SQ_free_result(sql_result); sql_result=NULL; }
 306  
 307  if(sql_str) {
 308   id = atol(sql_str);
 309   free(sql_str);
 310  }
 311  else id=-1;
 312  
 313  return(id);
 314  
 315 }
 316 
 317 
 318 /************************************************************
 319 * get_qresult_str()                                         *
 320 *                                                           *
 321 * Returns string containing query result                    *
 322 *                                                           *
 323 *                                                           *
 324 * Returns:                                                  *
 325 *  String containing the result.Needs to be freed after use *
 326 *  NULL in case of an error                                 *
 327 *  - SQL error                                              *
 328 *  - if query returns more than one string (row)            *
 329 *                                                           *
 330 *************************************************************/
 331 char *get_qresult_str(SQ_connection_t *sql_connection, char *query)
     /* [<][>][^][v][top][bottom][index][help] */
 332 {
 333 SQ_result_set_t *sql_result;
 334 SQ_row_t *sql_row;
 335 char *sql_str;
 336 int sql_err;
 337 
 338 
 339  ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s [%s]", UD_TAG, query);
 340  sql_err=SQ_execute_query(sql_connection, query, &sql_result);
 341  
 342  if(sql_err) {
 343     ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(sql_connection), query);
 344     die;
 345  }
 346         
 347          
 348  if ((sql_row = SQ_row_next(sql_result)) != NULL) {
 349         sql_str = SQ_get_column_string(sql_result, sql_row, 0);
 350 
 351      /* We must process all the rows of the result,*/
 352      /* otherwise we'll have them as part of the next qry */
 353         while ( (sql_row = SQ_row_next(sql_result)) != NULL) {
 354           ER_perror(FAC_UD, UD_SQL, "duplicate PK [%s]\n", query); 
 355           if(sql_str)free(sql_str); sql_str=NULL;
 356         }
 357  }
 358  else sql_str=NULL;
 359  
 360  SQ_free_result(sql_result);
 361  return(sql_str);
 362 }
 363 
 364 
 365 
 366 /************************************************************
 367 * get_field_str()                                           *
 368 *                                                           *
 369 * Returns string containing the field.                      *
 370 *  field - field name to be retrieved                       *
 371 *  ref_tbl_name - name of the table containing the field    *
 372 *  ref_name - reference name                                *
 373 *  attr_value - reference value                             *
 374 *  condition - additional condition ( f.e. 'AND dummy=0'    *
 375 *                                                           *
 376 * Returns:                                                  *
 377 *  String containing the field. Needs to be freed after use *
 378 *  NULL in case of an error                                 *
 379 *                                                           *
 380 *************************************************************/
 381 char *get_field_str(SQ_connection_t *sql_connection, char *field, 
     /* [<][>][^][v][top][bottom][index][help] */
 382                            char *ref_tbl_name, char *ref_name, 
 383                            char * attr_value, char *condition)
 384 {
 385 char query[STR_L];
 386 
 387  sprintf(query, "SELECT %s FROM %s "
 388                 "WHERE %s='%s' ",
 389                 field, ref_tbl_name, ref_name, attr_value);
 390  if (condition)strcat(query, condition);
 391 
 392  return( get_qresult_str(sql_connection, query));
 393 
 394 } 
 395 
 396 /************************************************************
 397 * long get_sequence_id(Transaction_t *tr)
 398 * >0 - success
 399 * -1 - sql error
 400 *
 401 * **********************************************************/
 402 
 403 long get_sequence_id(Transaction_t *tr)
     /* [<][>][^][v][top][bottom][index][help] */
 404 {
 405 char *sql_str;
 406 char str_id[STR_M];
 407 long sequence_id=-1;
 408 
 409 
 410   sprintf(str_id, "%ld", tr->object_id);
 411   sql_str= get_field_str(tr->sql_connection, "sequence_id", "last", "object_id", str_id, NULL);
 412   if(sql_str) {
 413           sequence_id = atol(sql_str);
 414           free(sql_str);
 415   }
 416   
 417   return(sequence_id);
 418 
 419 }
 420 
 421 
 422 /************************************************************
 423 * long get_ref_id(char *ref_tbl_name, char *ref_name, char * attr_value)
 424 * >0 - success
 425 * -1 - sql error
 426 *
 427 * **********************************************************/
 428 
 429 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] */
 430 {
 431 char *sql_str;
 432 long ref_id=-1;
 433 
 434         sql_str= get_field_str(tr->sql_connection, "object_id", ref_tbl_name, ref_name, attr_value, condition);
 435         if(sql_str) {
 436                  ref_id = atol(sql_str);
 437                  free(sql_str);
 438         }
 439         return(ref_id); 
 440 }
 441 
 442 
 443 /************************************************************
 444 * int isdummy()
 445 *
 446 * Returns 1 if the object in question is a dummy, 
 447 * otherwise returns 0.
 448 * 
 449 * In case of error:
 450 * -1 - sql error or object does not exist
 451 *
 452 ***********************************************************/
 453 
 454 int isdummy(Transaction_t *tr)
     /* [<][>][^][v][top][bottom][index][help] */
 455 {
 456 char *sql_str;
 457 char str_id[STR_M];
 458 int object_type=-1;
 459 
 460   sprintf(str_id, "%ld", tr->object_id);
 461   sql_str= get_field_str(tr->sql_connection, "object_type", "last", "object_id", str_id, NULL);
 462   if(sql_str) {
 463           object_type = atoi(sql_str);
 464           free(sql_str);
 465   }
 466   
 467   if (object_type==-1) {
 468    ER_perror(FAC_UD, UD_SQL, "cannot get object type\n");
 469    die;
 470   } 
 471   if (object_type==DUMMY_TYPE) return(1);
 472   else return(0);
 473 
 474 }
 475 
 476 /* it may be either a legacy name reference, or a nic-handle  */
 477 /* we rely on other parsers/syntax checkers, so no surprises  */
 478 /* thus, the check is simple - if there is a space - not a nh */
 479 static int isnichandle(char *name)
     /* [<][>][^][v][top][bottom][index][help] */
 480 {
 481  if(index(name, ' ')) return(0);
 482  else return(1);        
 483 }
 484 
 485 
 486 /************************************************************
 487 * process_reverse_domain()                                  *
 488 *                                                           *
 489 * Tries to insert additional data for reverse domains       *
 490 * This data includes prefix and perfix length for reverse   *
 491 * delegation block. It is stored in inaddr_arpa table for   *
 492 * IPv4 and ip6int table for IPv6 address spaces             *
 493 *                                                           *
 494 * Returns:                                                  *
 495 * 0  success                                                *
 496 * -1 sql error                                              *
 497 *                                                           *
 498 *************************************************************/
 499 
 500 static int process_reverse_domain(Transaction_t *tr, 
     /* [<][>][^][v][top][bottom][index][help] */
 501                                   ip_prefix_t *prefptr,
 502                                   int op)
 503 {
 504   unsigned prefix, prefix_length; /* ipv4 */
 505   ip_v6word_t msb, lsb;          /* ipv6 */
 506   char query[STR_L];
 507   int num;
 508   int sql_err;
 509 
 510                                   
 511   if( IP_pref_b2_space(prefptr) == IP_V4 ) {  /* ipv4 */
 512     if(op==0) { /* insert record */
 513       IP_revd_b2v4(prefptr, &prefix, &prefix_length);
 514       sprintf(query, "INSERT INTO inaddr_arpa SET thread_id=%d, object_id=%ld, prefix=%u, prefix_length=%d ", 
 515               tr->thread_ins, tr->object_id, prefix, prefix_length);
 516     }
 517     else {
 518       /* update record */
 519       sprintf(query, "UPDATE inaddr_arpa SET thread_id=%d WHERE object_id=%ld ", 
 520               tr->thread_upd, tr->object_id);
 521     }
 522   }
 523   else { /* ipv6 */
 524     if(op==0) { /* insert record */   
 525       IP_revd_b2v6(prefptr, &msb, &lsb, &prefix_length);
 526       sprintf(query, "INSERT INTO ip6int SET thread_id=%d, object_id=%ld, msb='%llu', lsb='%llu', prefix_length=%d ", 
 527               tr->thread_ins, tr->object_id, msb, lsb, prefix_length);
 528     }
 529     else {
 530       /* update record */
 531       sprintf(query, "UPDATE ip6int SET thread_id=%d WHERE object_id=%ld ", 
 532               tr->thread_upd, tr->object_id);
 533     }
 534   }
 535 
 536   ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s [%s]", UD_TAG, query);
 537   sql_err = SQ_execute_query(tr->sql_connection, query, (SQ_result_set_t **)NULL);
 538   num = mysql_affected_rows(tr->sql_connection); 
 539   
 540   /* Check for errors */
 541   if (sql_err) {
 542    ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query);
 543    die;
 544   }
 545   /* If nothing was affected then WHERE clause returned nothing - DB error */
 546   if(num == 0) {
 547    ER_perror(FAC_UD, UD_SQL, "insert inaddr had no effect [%s]\n", query);
 548    die;
 549   }       
 550   return(0);
 551 }
 552 
 553 #define insert_reverse_domain(tr, pr) process_reverse_domain(tr, pr, 0)
     /* [<][>][^][v][top][bottom][index][help] */
 554 #define update_reverse_domain(tr, pr) process_reverse_domain(tr, pr, 1)
     /* [<][>][^][v][top][bottom][index][help] */
 555 
 556 
 557 /************************************************************
 558 * auth_member_of()                                          *
 559 *                                                           *
 560 * Function that checks the authorization for membership     *
 561 * (i.e. if the object is authorized to be a memeber by      *
 562 * mbrs-by-ref attribute of the set is refers by member-of   *
 563 * attribute).                                               *
 564 * First checks if 'mbrs-by-ref: ANY'                        *
 565 * If not then checks that maintner referenced by            *
 566 * mbrs-by-ref attribute of the set is the one in mnt-by.    *
 567 *                                                           *
 568 * Returns:                                                  *
 569 * 0  success                                                *
 570 * 1  not allowed                                            *
 571 * -1 SQL error                                              *  
 572 *                                                           *
 573 *************************************************************/
 574 static int auth_member_of(Attribute_t *attr, Transaction_t *tr)
     /* [<][>][^][v][top][bottom][index][help] */
 575 {
 576 GString *query;
 577 char *set_name;
 578 char *qresult;
 579 
 580 /* Check if set has mbrs_by_ref==ANY 
 581    In such case mbrs_by_ref.mnt_id==0 
 582 */
 583 
 584  if ((query = g_string_sized_new(STR_XL)) == NULL){
 585   tr->succeeded=0;
 586   tr->error |= ERROR_U_MEM; 
 587   ER_perror(FAC_UD, UD_MEM, "cannot allocate gstring\n"); 
 588   die; 
 589  }
 590  
 591  set_name = get_set_name(tr->class_type);
 592 /* ER_dbg_va(FAC_UD, ASP_UD_OBJ, "%s set name retrieved: %s\n", UD_TAG, set_name);      */
 593 
 594 /* Check if the set protects itself with mbrs-by-ref attribute */
 595    g_string_sprintf(query,"SELECT COUNT(*) FROM mbrs_by_ref, %s "
 596                           "WHERE mbrs_by_ref.object_id=%s.object_id "
 597                           "AND %s.%s='%s' ",
 598                           set_name, set_name, set_name, set_name, attr->value);
 599 
 600    qresult = get_qresult_str(tr->sql_connection, query->str);
 601    /* should be '0' if there is no mbrs-by-ref attribute */
 602    if (strcmp(qresult, "0")==0){
 603            /* there is no mbrs-by-ref attribute - so we cannot go ahead */
 604            ER_dbg_va(FAC_UD, ASP_UD_OBJ, "[%ld] membership by reference is not allowed (no mbrs-by-ref) [%d:%s]", tr->transaction_id, attr->type, attr->value);
 605            g_string_free(query, TRUE);
 606            return(1);
 607    }
 608    else free(qresult);
 609 
 610 /* Check if membership is protected by the keyword "ANY" */
 611 /* There is a dummy mntmer object in the database corresponding to "ANY" */
 612 /* Its object_id==0 */
 613 /* EXAMPLE:
 614 
 615    SELECT route_set.object_id 
 616    FROM   mbrs_by_ref, route_set
 617    WHERE  mbrs_by_ref.object_id=route_set.object_id
 618    AND    route_set.route_set=<setname>
 619    AND    mbrs_by_ref.mnt_id=0
 620 */   
 621     g_string_sprintf(query,"SELECT %s.object_id FROM mbrs_by_ref, %s "
 622                            "WHERE mbrs_by_ref.object_id=%s.object_id "
 623                            "AND %s.%s='%s' AND mbrs_by_ref.mnt_id=0 ", 
 624                            set_name, set_name, set_name, set_name, set_name, attr->value);
 625   
 626     qresult = get_qresult_str(tr->sql_connection, query->str);
 627   /* if such record exists - go ahead */
 628     if(qresult) {
 629         free(qresult);  
 630         g_string_free(query, TRUE);
 631         return(0);  
 632     }
 633 
 634 /* Now check if our mnt_by belongs to mbrs_by_ref list of the set */
 635 /* we search only mnt_by.thread_id!=0 to check against new/updated mnt-by attribute */
 636     g_string_sprintf(query, "SELECT mbrs_by_ref.object_id FROM %s, mbrs_by_ref, mnt_by "
 637                             "WHERE mbrs_by_ref.mnt_id=mnt_by.mnt_id "
 638                             "AND mnt_by.object_id=%ld "
 639                             "AND %s.object_id=mbrs_by_ref.object_id "
 640                             "AND %s.%s='%s' "
 641                             "AND ( mnt_by.thread_id=%d OR mnt_by.thread_id=%d ) ",
 642                             set_name, tr->object_id, set_name, set_name, set_name, attr->value, tr->thread_upd, tr->thread_ins);
 643 
 644     qresult = get_qresult_str(tr->sql_connection, query->str);
 645     /* If our mntner is listed (non-empty result)  membership is authorized */
 646     if (qresult) {
 647          free(qresult);g_string_free(query, TRUE);
 648          return(0);
 649     } else {
 650          ER_dbg_va(FAC_UD, ASP_UD_OBJ, "[%ld] membership by reference is not autorized [%d:%s]", tr->transaction_id, attr->type, attr->value);
 651          g_string_free(query, TRUE);
 652          return(1);
 653     }
 654  }/* auth_member_of()  */
 655         
 656 
 657 /************************************************************
 658 * create_dummy()                                            *
 659 *                                                           *
 660 * Function that creates a dummy object (that is one that    *
 661 * is referenced from an object but does not                 *
 662 * exist in the database).                                   *
 663 * Dummy object exists only in relevant main and 'last'      *
 664 * tables. Its creation is controlled by tr->dummy_allowed.  *
 665 * Queries for the dummies are defined in Dummy[] array.     *
 666 *                                                           *
 667 * Returns:                                                  *
 668 * 0  success                                                *
 669 * 1  no rf integrity and dummy not allowed                  *
 670 * -1 SQL error                                              *
 671 *                                                           *
 672 *************************************************************/
 673 static int create_dummy(Attribute_t *attr, Transaction_t *tr) 
     /* [<][>][^][v][top][bottom][index][help] */
 674 {
 675 const char *query_fmt;
 676 long dummy_id;
 677 char query[STR_L];
 678 int result=0;
 679 char *set_name;
 680 char *p_name;
 681 int query_type;
 682 long timestamp;
 683 char str_id[STR_M];
 684 gchar *attr_value=NULL;
 685 int sql_err;
 686 char *token=NULL;
 687 
 688   query_fmt = DF_get_dummy_query(attr->type);
 689   if (strcmp(query_fmt, "") == 0) { 
 690      ER_perror(FAC_UD, UD_BUG, "empty query string\n");
 691      die;
 692   }
 693   
 694   /* We allow creating dummy sets in any mode */
 695   /* For others attributes return if we are in protected mode */
 696   if ((attr->type!=A_MO) &&  (!IS_DUMMY_ALLOWED(tr->mode))) return(1);
 697 
 698   /* Insert dummy in the last table */
 699   /* Calculate the object_id - should be max+1 */
 700   dummy_id = get_minmax_id(tr->sql_connection, "object_id", "last", 1) +1;
 701  /* Record dummy's object_id, it'll be needed in commit/rollback */
 702   tr->dummy_id[tr->ndummy]=dummy_id; tr->ndummy++;
 703 
 704   /* Update the TR for crash recovery */
 705   /* If we crash before actually creating an entry in last */
 706   /* there should be no harm - later in rollback we will just try to delete nonexistent object */
 707   TR_update_dummy(tr);
 708 
 709   sprintf(str_id, "%ld", tr->object_id);
 710   timestamp=time(NULL);
 711   sprintf(query, "INSERT INTO last SET thread_id=%d, timestamp=%ld, object_type=%d, object='DUMMY for %s'", 
 712                   tr->thread_ins, timestamp, DUMMY_TYPE, str_id);
 713   
 714   ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s [%s]", UD_TAG, query);
 715   sql_err = SQ_execute_query(tr->sql_connection, query, (SQ_result_set_t **)NULL);
 716   
 717   /* Check for errors */
 718   if (sql_err) {
 719    ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query);    
 720    die;
 721   }     
 722         
 723   /* check that the dummy_id is correct */
 724   if(dummy_id != mysql_insert_id(tr->sql_connection)) die; /* probably implementation of autoincrement changed */
 725 
 726    
 727   /* compose the query */
 728   query_type=DF_get_dummy_query_type(attr->type);
 729   switch (query_type) { 
 730          
 731          /* person_role */
 732          case UD_AX_PR:
 733               sprintf(query, query_fmt, tr->thread_ins, dummy_id, attr->value, DUMMY_TYPE);
 734               break;
 735          
 736          /* maintner */
 737          case UD_AX_MT: 
 738               sprintf(query, query_fmt, tr->thread_ins, dummy_id, attr->value, DUMMY_TYPE);
 739               break;
 740          
 741          /* as_set, route_set */
 742          case UD_AX_MO: 
 743               set_name = get_set_name(tr->class_type);
 744               sprintf(query, query_fmt, set_name, tr->thread_ins, dummy_id, set_name, attr->value);       
 745               break;
 746               
 747          default:
 748               ER_perror(FAC_UD, UD_BUG, "query not defined for this type of attribute[%d]\n", attr->type);
 749               die;
 750               break;
 751   }
 752         
 753   ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s [%s]", UD_TAG, query);
 754   sql_err = SQ_execute_query(tr->sql_connection, query, (SQ_result_set_t **)NULL);
 755   if (sql_err) {
 756    ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query);
 757    die;
 758   }
 759   
 760   /* for legacy person/role reference (without nic-handle) create records in names table */
 761   if( (query_type == UD_AX_PR) && (!isnichandle (attr->value)) ){
 762    /* parse the names */
 763     /*ER_dbg_va(FAC_UD, ASP_UD_OBJ, "%s adding names for dummy\n", UD_TAG);*/
 764     query_fmt = DF_get_insert_query(A_PN);
 765     attr_value = g_strdup(attr->value); 
 766     token = attr_value;
 767     while((p_name=strsep(&token, " "))){
 768                 sprintf(query, query_fmt, tr->thread_ins, dummy_id, DUMMY_TYPE, p_name);
 769                 ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s [%s]", UD_TAG, query);
 770                 sql_err = SQ_execute_query(tr->sql_connection, query, (SQ_result_set_t **)NULL);
 771                 if (sql_err)
 772                  if(SQ_errno(tr->sql_connection) != ER_DUP_ENTRY) {
 773                   ER_perror(FAC_UD, UD_SQL, "insert dummy names:%s[%s]\n", SQ_error(tr->sql_connection), query);
 774                   result=-1;
 775                  }
 776     }
 777     free(attr_value);
 778   }
 779  return(result);
 780 }
 781 
 782 /************************************************************
 783 * update_attr()                                             *
 784 *                                                           *
 785 * Function that updates an attribute if it already exists.  *
 786 * Called from each_attribute_proces() function if it        *
 787 * cannot insert the row.                                    *
 788 * Queries for the attributes are defined in Update[] array. *
 789 *                                                           *
 790 * Returns: Nothing. Error code is stored in tr->error.      *
 791 *                                                           *
 792 *************************************************************/
 793 static void update_attr(Attribute_t *attr, Transaction_t *tr)
     /* [<][>][^][v][top][bottom][index][help] */
 794 {
 795 int num;
 796 const char *query_fmt;
 797 char *set_name;
 798 unsigned int if_address;
 799 char * rf_host;
 800 int rf_port, rf_type;
 801 char *a_value;
 802 int sq_info[3];
 803 char * condition;
 804 char *sq_error;
 805 char query[STR_XL];
 806 ip_prefix_t dn_pref;
 807 int sql_err;
 808 char *token;
 809 char *mu_mntner;
 810 
 811 
 812 /* It may be needed to update second attribute stored in the main table, like inetnum, filter-set, etc. */
 813  if((tr->load_pass!=0)&&(DF_get_update_query_type(attr->type)!=UD_MA_U2)) return;
 814 
 815 /*      ER_dbg_va(FAC_UD, ASP_UD_OBJ, "%s updating attribute...\n", UD_TAG);*/
 816 
 817    /* Do some additional processing for reverse domains */
 818    /* XXX Later we will implement this under UD_MA_DN case */
 819    if ((attr->type == A_DN) && (IP_revd_a2b(&dn_pref, attr->value)==IP_OK)) {
 820      if(update_reverse_domain(tr, &dn_pref) !=0 ){
 821        tr->error|=ERROR_U_DBS;
 822        tr->succeeded=0;
 823        g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:%s\n" ,
 824                          ERROR_U_DBS, attr->type, attr->value, SQ_error(tr->sql_connection));   
 825      }
 826    }
 827    
 828    /* get query format string */
 829    query_fmt =  DF_get_update_query(attr->type);
 830 
 831    if (strcmp(query_fmt, "") == 0) return;
 832 
 833    switch (DF_get_update_query_type(attr->type)) {
 834          case UD_MAIN_: sprintf(query, query_fmt, tr->thread_upd, tr->object_id);
 835                         break;
 836          case UD_MA_PR: 
 837                         sprintf(query, query_fmt, tr->thread_upd, tr->class_type, tr->object_id);
 838                         break;  
 839          case UD_MA_U2: /* save the new value of the attribute for commit*/
 840                   /* this is necessary for filter(filter-set), netname (inet?num), */
 841                   /* local-as(inet-rtr) attributes, as they are another field in the record */
 842                         if((tr->load_pass != 0)){
 843                       /* for fast loader we need to update the field as we have no commit */
 844                           sprintf(query, query_fmt, DF_get_class_sql_table(tr->class_type), 0, attr->value, tr->object_id);
 845                         }
 846                         else {
 847                          tr->save=g_strdup(attr->value);
 848 /*                       ER_dbg_va(FAC_UD, ASP_UD_OBJ, "%s u2 saved [%s]\n", UD_TAG, tr->save); */
 849                          /* update TR for crash recovery */
 850                          TR_update_save(tr);
 851                          return;
 852                         }        
 853                         break;                  
 854          case UD_AX_PR:
 855                         /* This is for non-conformant admin-c, etc.*/
 856                         a_value=attr->value;
 857                         if(strlen(attr->value)>MAX_NIC_HDL)*(attr->value + MAX_NIC_HDL)='\0';
 858                         
 859                         if (!IS_DUMMY_ALLOWED(tr->mode))condition="AND dummy=0 "; else condition=NULL;
 860                         sprintf(query, query_fmt, tr->thread_upd, tr->object_id, 
 861                                 get_ref_id(tr, "person_role", "nic_hdl", attr->value, condition));
 862                         break;
 863          case UD_AX_MT: 
 864                         if (!IS_DUMMY_ALLOWED(tr->mode))condition="AND dummy=0 "; else condition=NULL;
 865                         sprintf(query, query_fmt, tr->thread_upd, tr->object_id, 
 866                                 get_ref_id(tr, "mntner", "mntner", attr->value, condition));
 867                         break;
 868          case UD_AX_MU: /* for mnt_routes table*/
 869                         a_value=g_strdup(attr->value); 
 870                         token = a_value;
 871                         mu_mntner=strsep(&token, " ");
 872                         if (!IS_DUMMY_ALLOWED(tr->mode))condition="AND dummy=0 "; else condition=NULL;
 873                         sprintf(query, query_fmt, tr->thread_upd, tr->object_id, 
 874                                 get_ref_id(tr, "mntner", "mntner", mu_mntner, condition));
 875                         free(a_value);
 876                         break;
 877          case UD_AX_MO: 
 878                         set_name = get_set_name(tr->class_type);
 879 /*                    ER_dbg_va(FAC_UD, ASP_UD_OBJ, "%s retrieved set name: %s\n", UD_TAG, set_name);*/
 880                         if (!IS_DUMMY_ALLOWED(tr->mode))condition="AND dummy=0 "; else condition=NULL;
 881                         sprintf(query, query_fmt, tr->thread_upd, tr->object_id, 
 882                                         get_ref_id(tr, set_name, set_name, attr->value, condition));
 883                         break;                          
 884          case UD_AX_MR:
 885                         if ((strcmp(attr->value, "ANY")==0) || (strcmp(attr->value, "any")==0) || (strcmp(attr->value, "Any")==0))
 886                         sprintf(query, query_fmt, tr->thread_upd, tr->object_id, 
 887                                 get_ref_id(tr, "mntner", "mntner", "ANY",NULL));
 888                         else {  
 889                          if (!IS_DUMMY_ALLOWED(tr->mode))condition="AND dummy=0 "; else condition=NULL;
 890                          sprintf(query, query_fmt, tr->thread_upd, tr->object_id, 
 891                                 get_ref_id(tr, "mntner", "mntner", attr->value, condition));
 892                         }
 893                         break;
 894          case UD_LEAF_: 
 895                         sprintf(query, query_fmt, tr->thread_upd, tr->object_id, attr->value);
 896                         break;
 897          case UD_LF_IF:
 898                 /* Convert ascii ip -> numeric one */
 899                         convert_if(attr->value, &if_address);
 900                         sprintf(query, query_fmt, tr->thread_upd, tr->object_id, if_address);
 901                         break;
 902          case UD_LF_RF:
 903                         rf_host=convert_rf(attr->value, &rf_type, &rf_port);
 904                         sprintf(query, query_fmt, tr->thread_upd, tr->object_id, rf_type, rf_host, rf_port);
 905                         if(rf_host)free(rf_host);
 906                         break;                  
 907          case UD_LF_AY:
 908                         sprintf(query, query_fmt, tr->thread_upd, tr->object_id, convert_time(attr->value));
 909                         break;          
 910            default:
 911                         tr->error|=ERROR_U_BUG;
 912                         tr->succeeded=0;
 913                         g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:no update qry\n" ,ERROR_U_BUG, attr->type, attr->value);
 914                         ER_perror(FAC_UD, UD_BUG, "query not defined for this type of attribute:[%d:%s]\n", attr->type, attr->value);
 915                         die;
 916                         break;
 917         }
 918    /* Execute the query */
 919     ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s [%s]", UD_TAG, query);
 920     sql_err = SQ_execute_query(tr->sql_connection, query, (SQ_result_set_t **)NULL);
 921     if(sql_err) { /* an error occured*/
 922      /* Error - copy the error condition and return */
 923         sq_error=SQ_error(tr->sql_connection);
 924         ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", sq_error, query);
 925         tr->error|=ERROR_U_DBS;
 926         tr->succeeded=0;
 927         g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:%s\n" ,ERROR_U_DBS, attr->type, attr->value, sq_error);
 928         ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query);
 929         die;
 930     }
 931     else {
 932      /* Query OK */
 933       num = mysql_affected_rows(tr->sql_connection);
 934       if(num == 0) { /* check for duplicates*/
 935         SQ_get_info(tr->sql_connection, sq_info); /* UPDATE ... SET*/
 936         if ((sq_info[SQL_DUPLICATES]==0) && (sq_info[SQL_MATCHES]==0)) { 
 937         /* Condition with zero duplicates and matches may occur when the object is a dummy */
 938         /* and we are running in protected mode ( dummies are not allowed, tr->dummy==0). */
 939         /* In such case we will append "AND dummy=0" to the query, which won't */
 940         /* return a match if the object in question is a dummy */
 941           ER_inf_va(FAC_UD, ASP_UD_UPDLOG, "[%ld] dummy prevents update: [%s]", tr->transaction_id, query);
 942           tr->error|=ERROR_U_OBJ;
 943           tr->succeeded=0;
 944           g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:dummy update\n" ,ERROR_U_OBJ, attr->type, attr->value);
 945         } /* else duplicate entry - silently drop it  */
 946       } 
 947       /* For member_of attribute we need to check membership claim in protected mode */
 948       if ((attr->type == A_MO) && (!IS_DUMMY_ALLOWED(tr->mode))){
 949           if(auth_member_of(attr, tr)!=0){
 950           tr->error|=ERROR_U_AUT;
 951           tr->succeeded=0;
 952           ER_inf_va(FAC_UD, ASP_UD_UPDLOG, "[%ld] membership by reference is not allowed [%d:%s]", tr->transaction_id, attr->type, attr->value);
 953           g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:membership not allowed\n" ,ERROR_U_AUT, attr->type, attr->value);    
 954         }
 955       }
 956     }  
 957 return;
 958 }/*  update_attr()  */
 959 
 960 
 961 /************************************************************
 962 * each_attribute_proces()                                   *
 963 *                                                           *
 964 * Main function that processes object attributes one by one.*
 965 * Called from g_slist_foreach() function.                   * 
 966 * First it tries to insert an attribute.                    *
 967 * If an error it assumes that attribute is already in       *
 968 * a table and calls update_attr() to update it.             *
 969 * Queries for the attributes are defined in Insert[] array. * 
 970 *                                                           *
 971 * Returns: Nothing. Error code is stored in tr->error.      *
 972 *                                                           *
 973 *************************************************************/
 974 static void each_attribute_process(void *element_data, void *tr_ptr) 
     /* [<][>][^][v][top][bottom][index][help] */
 975 {
 976 int num;
 977 const char *query_fmt;
 978 int query_type;
 979 int do_query;
 980 Attribute_t *attr = element_data;
 981 Transaction_t *tr = (Transaction_t *)tr_ptr;
 982 unsigned int prefix, prefix_length, if_address;
 983 unsigned int begin_in, end_in;
 984 ip_v6word_t  high, low;
 985 
 986 int begin_as, end_as;
 987 char query[STR_XL];
 988 char * set_name;
 989 char * rf_host; /* needs to be freed after use*/
 990 int rf_type, rf_port;
 991 char *a_value;
 992 int sq_info[3];
 993 char *mu_mntner, *mu_prefix;
 994 int dummy_err;
 995 char *sq_error;
 996 ip_prefix_t dn_pref;
 997 int sql_err;
 998 int res;
 999 char *token;
1000 
1001 /* we still want to continue to collect all possible errors*/
1002 /*  if(tr->succeeded == 0) return; */
1003  
1004  /* To switch off querying for some types of attributes */
1005   do_query=1;
1006   
1007  /* Determine the query type */ 
1008   query_type=DF_get_insert_query_type(attr->type);
1009 
1010 /* For loadind pass #1 we need to process only main tables */
1011   if(tr->load_pass==1){ 
1012         switch(query_type) {
1013          case UD_MAIN_:
1014          case UD_MA_U2:
1015          case UD_MA_PR:
1016          case UD_MA_RT:
1017          case UD_MA_IN:
1018          case UD_MA_I6:
1019          case UD_MA_OR:
1020          case UD_MA_AK:
1021                         break;
1022          default:       return; /* return for other than MAIN tables*/
1023         }
1024   }
1025   
1026     query_fmt = DF_get_insert_query(attr->type);
1027 
1028 /* return if no query is defined for this attribute */
1029   if (strcmp(query_fmt, "") == 0) return;
1030 
1031  /* compose the query depending on the attribute */
1032   switch (query_type) {
1033    case UD_MAIN_: /* for MAIN tables */
1034                 if (ACT_UPDATE(tr->action)) do_query=0;
1035                 else
1036                 sprintf(query, query_fmt, tr->thread_ins, tr->object_id, attr->value);
1037                 break;
1038    case UD_MA_OR: /* for the origin attribute */
1039                 if (ACT_UPDATE(tr->action)) do_query=0;
1040                 else {
1041                   sprintf(query, query_fmt, tr->thread_ins, attr->value, tr->object_id);
1042                   tr->action |= TA_UPD_RX;
1043                   RP_pack_set_orig(attr->type, tr->packptr, attr->value);
1044                 }
1045                 break;
1046    case UD_MA_PR: /* for person_role table*/
1047                 if (ACT_UPDATE(tr->action)) do_query=0;
1048                 else
1049                  sprintf(query, query_fmt, tr->thread_ins, tr->class_type, tr->object_id,  attr->value);
1050                 
1051                 /* check if we need to update NHR */
1052                 if (ACT_UPD_NHR(tr->action)) {
1053                  /* Check if we can allocate it */       
1054                   res = NH_check(tr->nh, tr->sql_connection);
1055                   if(res == -1) { /* we cannot allocate this NIC handle (DB error) */
1056                      tr->succeeded=0;
1057                      tr->error |= ERROR_U_DBS;
1058                      g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:cannot allocate nic-handle\n", ERROR_U_DBS, attr->type, attr->value);
1059                      ER_perror(FAC_UD, UD_SQL, "cannot allocate nic hdl[%s]\n", attr->value);
1060                      die; 
1061                   }
1062                   else 
1063                   if(res == 0) { /* we cannot allocate this NIC handle (full space or ID in use) */
1064                     tr->succeeded=0; 
1065                     tr->error |= ERROR_U_OBJ;
1066                     g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:nic-handle already in use\n", ERROR_U_OBJ, attr->type, attr->value); 
1067                     return;
1068                   }
1069                 }
1070                 break;  
1071    case UD_MA_RT: /* for route table*/
1072                 if (ACT_UPDATE(tr->action)) do_query=0;
1073                 else {
1074                   tr->action |= TA_UPD_RX;
1075                   RP_pack_set_pref4(attr->type, attr->value, tr->packptr, &prefix, &prefix_length);
1076                   /*ER_dbg_va(FAC_UD, ASP_UD_OBJ, "%s route: %u/%u\n", UD_TAG, prefix, prefix_length);                  */
1077                   sprintf(query, query_fmt, tr->thread_ins,  
1078                           tr->object_id, prefix, prefix_length);
1079                 }
1080                 break;
1081    case UD_MA_IN: /* for inetnum table*/
1082                 if (ACT_UPDATE(tr->action)) do_query=0;
1083                 else {
1084                   tr->action |= TA_UPD_RX;
1085                   RP_pack_set_rang(attr->type, attr->value, tr->packptr, &begin_in, &end_in);
1086                   /* XXX error handling ? */
1087                   sprintf(query, query_fmt, tr->thread_ins, tr->object_id, begin_in, end_in);
1088                 }       
1089                 break;
1090    case UD_MA_I6: /* for inet6num table*/
1091                 if (ACT_UPDATE(tr->action)) do_query=0;
1092                 else {
1093                   tr->action |= TA_UPD_RX;
1094                   RP_pack_set_pref6(attr->type, attr->value, tr->packptr, &high, &low, &prefix_length);
1095                   /* XXX error handling ? */
1096                   sprintf(query, query_fmt, tr->thread_ins, tr->object_id, high, low, prefix_length);
1097                 }       
1098                 break;  
1099    case UD_MA_U2: /* This is actually an update - go to update_attr - this is more natural */
1100                  do_query=0;
1101                 break;
1102    case UD_MA_AK: /* for as_block table*/
1103                 if (ACT_UPDATE(tr->action)) do_query=0;
1104                 else {
1105                   convert_as_range(attr->value, &begin_as, &end_as);
1106                   sprintf(query, query_fmt, tr->thread_ins, tr->object_id, begin_as, end_as);
1107                 }
1108                 break;                          
1109    case UD_AUX__: /* for AUX tables*/
1110                 if((attr->type==A_AC) || (attr->type==A_TC) || (attr->type==A_ZC))
1111                  if(strlen(attr->value)>MAX_NIC_HDL)*(attr->value + MAX_NIC_HDL)='\0';
1112 
1113                 sprintf(query, query_fmt, tr->thread_ins, tr->object_id, tr->class_type, attr->value);
1114                 if(!IS_DUMMY_ALLOWED(tr->mode))strcat(query, " AND dummy=0 ");
1115                 break;
1116    case UD_AX_MO: /* for member_of table*/
1117                 set_name = get_set_name(tr->class_type);
1118 /*              ER_dbg_va(FAC_UD, ASP_UD_OBJ, "%s retrieved set name: %s\n", UD_TAG, set_name);*/
1119                 sprintf(query, query_fmt, tr->thread_ins,  
1120                  tr->object_id, set_name, tr->class_type, set_name, set_name, set_name, attr->value);
1121                 break;  
1122    case UD_AX_MR: /* for mbrs_by_ref table*/
1123                 if ((strcmp(attr->value, "ANY")==0) || (strcmp(attr->value, "any")==0) || (strcmp(attr->value, "Any")==0))
1124                  sprintf(query, query_fmt, tr->thread_ins, tr->object_id, tr->class_type, "ANY");
1125                 else  
1126                  sprintf(query, query_fmt, tr->thread_ins, tr->object_id, tr->class_type, attr->value);
1127                 break;  
1128    case UD_AX_MU: /* for mnt_routes table*/
1129                 a_value=g_strdup(attr->value); 
1130                 token = a_value;
1131                 mu_mntner=strsep(&token, " ");
1132                 mu_prefix=token;
1133                 sprintf(query, query_fmt, tr->thread_ins, tr->object_id, tr->class_type, mu_mntner);
1134                 free(a_value);
1135                 if (!IS_DUMMY_ALLOWED(tr->mode))strcat(query, " AND dummy=0 ");
1136                 break;
1137    case UD_LEAF_: /* for LEAF tables*/
1138                 sprintf(query, query_fmt, tr->thread_ins, tr->object_id, attr->value);
1139                 break;
1140    case UD_LF_OT: /* for LEAF tables containing object_type field*/
1141                 sprintf(query, query_fmt, tr->thread_ins, tr->object_id, tr->class_type, attr->value);
1142                 break;                          
1143    case UD_LF_AT: /* check PGPKEY. If yes - check the existence of key-cert.*/
1144                 if(!IS_DUMMY_ALLOWED(tr->mode)){
1145                  if(strncmp("PGPKEY", attr->value, 6)==0) {
1146                    if(get_ref_id(tr, "key_cert", "key_cert", attr->value, NULL)<=0) { 
1147                     ER_inf_va(FAC_UD, ASP_UD_UPDLOG, "[%ld] no key-cert object[%s]", tr->transaction_id, attr->value);
1148                     tr->error|=ERROR_U_OBJ;
1149                     tr->succeeded=0;
1150                     g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:no key-cert object\n" ,ERROR_U_OBJ, attr->type, attr->value);
1151                     return;
1152                    }
1153                  }
1154                 } 
1155                 sprintf(query, query_fmt, tr->thread_ins, tr->object_id, tr->class_type, attr->value);
1156                 break;      
1157    case UD_LF_IF: /* for ifaddr tables*/
1158                 /* Convert ascii ip -> numeric one*/
1159                 convert_if(attr->value, &if_address);
1160                 sprintf(query, query_fmt, tr->thread_ins, tr->object_id, if_address);
1161                 break;
1162    case UD_LF_RF: /* for refer table*/
1163                 rf_host=convert_rf(attr->value, &rf_type, &rf_port);
1164                 sprintf(query, query_fmt, tr->thread_ins, tr->object_id, rf_type, rf_host, rf_port);
1165                 if(rf_host)free(rf_host);
1166                 break;  
1167    case UD_LF_AY: /* for auth_override table*/
1168                 sprintf(query, query_fmt, tr->thread_ins, tr->object_id, convert_time(attr->value));
1169                 break;
1170         default:
1171                 tr->succeeded=0;
1172                 tr->error |= ERROR_U_BUG;
1173                 g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:query not defined for the attribute\n" ,ERROR_U_BUG, attr->type, attr->value);
1174                 ER_perror(FAC_UD, UD_BUG, "query not defined for this type of attribute:[%d:%s]\n", attr->type, attr->value);
1175                 die;
1176                 break;
1177   }
1178   
1179  /* Make the query. For primary keys go straight to updates if we are updating the object */
1180   if(do_query){
1181    ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s [%s]", UD_TAG, query);
1182    sql_err = SQ_execute_query(tr->sql_connection, query, (SQ_result_set_t **)NULL);
1183   } 
1184   else {
1185    update_attr(attr, tr);
1186    return;
1187   }
1188   
1189   if (sql_err)  {
1190   /* we received an error */
1191    if(SQ_errno(tr->sql_connection) == ER_DUP_ENTRY){ /* Only error "Duplicate entry" may be considered*/
1192         if (ACT_UPDATE(tr->action)) { /* In update mode this is common (so actually not an error)*/
1193                 update_attr(attr, tr);
1194                 return;
1195         }       
1196      /* Otherwise this is a duplicate attribute, just ignore it */
1197      /* In the future if we are more stringent, checks may be added here */     
1198    }
1199    else { /* Other errors reveal a database/server problem*/
1200         sq_error=SQ_error(tr->sql_connection);
1201         tr->error|=ERROR_U_DBS;
1202         tr->succeeded=0;
1203         ER_perror(FAC_UD, UD_BUG, "%s[%s]\n", sq_error, query);
1204         g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:%s\n" ,ERROR_U_DBS, attr->type, attr->value, sq_error);
1205         die;
1206    }
1207   } /* if error occured */
1208   else { 
1209  /* If the query was successful */
1210    num = mysql_affected_rows(tr->sql_connection);
1211    if(num>0){ /* this is OK*/
1212  /* Do some additional processing for member_of attribute  */
1213         if ((attr->type == A_MO) && (!IS_DUMMY_ALLOWED(tr->mode))){
1214 /*              ER_dbg_va(FAC_UD, ASP_UD_OBJ, "%s need to auth membership\n", UD_TAG);*/
1215                 if(auth_member_of(attr, tr)!=0){
1216                  tr->error|=ERROR_U_AUT;
1217                  tr->succeeded=0;
1218                  ER_inf_va(FAC_UD, ASP_UD_UPDLOG, "[%ld] membership not allowed [%d:%s]", tr->transaction_id, attr->type, attr->value);
1219                  g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:membership not allowed\n" ,ERROR_U_AUT, attr->type, attr->value);     
1220                 }
1221         }
1222         else
1223           /* Do some additional processing for reverse zones domains */
1224           if ((attr->type == A_DN) 
1225               && IP_revd_a2b(&dn_pref, attr->value)==IP_OK ) {
1226             
1227             if(insert_reverse_domain(tr, &dn_pref) != 0 ) {
1228                 tr->error|=ERROR_U_DBS;
1229                 tr->succeeded=0;
1230                 ER_perror(FAC_UD, UD_SQL, "cannot insert inverse domain:[%d:%s]\n", attr->type, attr->value);
1231                 die;    
1232             }
1233             else {
1234               /* save data for the radix tree update */
1235               tr->action |= TA_UPD_RX;
1236               RP_pack_set_revd(attr->type, attr->value, tr->packptr);
1237             }
1238           }
1239         return;
1240    }
1241    if(num == 0) {
1242 /* this could be an empty update or a null select */        
1243         SQ_get_info(tr->sql_connection, sq_info); 
1244         if (sq_info[SQL_DUPLICATES]>0) {
1245         /* INSERT ... SELECT ... affected 0 rows, but there is 1 duplicate */
1246         /* which means that we already have such record in the table */ 
1247         /* this indicates that this is actually an update - update this attribute */     
1248                 if (sq_info[SQL_DUPLICATES]>1) { 
1249                         tr->error|=ERROR_U_DBS;
1250                         tr->succeeded=0;
1251                         ER_perror(FAC_UD, UD_SQL, "too many duplicates:[%d:%s]\n", attr->type, attr->value);
1252                         die;
1253                 }
1254                 update_attr(attr, tr);
1255         }
1256         else { 
1257         /* this is an emty SELECT because there is no referred object */        
1258         /* try to create dummy and repeat the original query*/
1259                 
1260 /*              ER_dbg_va(FAC_UD, ASP_UD_OBJ, "%s no ref. integrity. Trying to create dummy\n", UD_TAG);*/
1261 
1262                 dummy_err = create_dummy(attr, tr);
1263                 if (dummy_err == 0) {
1264                 /* Dummy was created */ 
1265                         g_string_sprintfa(tr->error_script,"W[%d][%d:%s]:dummy created\n" ,0, attr->type, attr->value);
1266                         ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s [%s]", UD_TAG, query);
1267                         sql_err = SQ_execute_query(tr->sql_connection, query, (SQ_result_set_t **)NULL);
1268                         num = mysql_affected_rows(tr->sql_connection);
1269                         if (sql_err) {
1270                           sq_error=SQ_error(tr->sql_connection);
1271                           ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", sq_error, query);
1272                           tr->error|=ERROR_U_DBS;
1273                           tr->succeeded=0;
1274                           g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:%s\n" ,
1275                                             ERROR_U_DBS, attr->type, attr->value, sq_error);
1276                           die;
1277                         }                    
1278                         if (num==0) {
1279                           ER_perror(FAC_UD, UD_SQL, "0 rows affected [%s]\n", query);
1280                           tr->error|=ERROR_U_DBS;
1281                           tr->succeeded=0;
1282                           g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:re-insert qry\n" ,
1283                                             ERROR_U_DBS, attr->type, attr->value);
1284                           die;
1285                         }
1286                 }
1287                 else 
1288                  if(dummy_err == 1) {
1289                  /* dummy not allowed */         
1290                    tr->error |= ERROR_U_OBJ;
1291                    tr->succeeded=0;
1292                    g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:dummy not allowed\n" ,ERROR_U_OBJ, attr->type, attr->value);
1293                    ER_inf_va(FAC_UD, ASP_UD_UPDLOG, "[%ld] dummy not allowed [%d:%s]", tr->transaction_id, attr->type, attr->value);
1294                  }
1295                  else {
1296                  /* SQL problem */       
1297                    tr->error|=ERROR_U_DBS;
1298                    tr->succeeded=0;
1299                    ER_perror(FAC_UD, UD_SQL, "dummy cannot be created [%d:%s]", attr->type, attr->value);
1300                    g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:dummy cannot be created\n" ,ERROR_U_DBS, attr->type, attr->value);
1301                    die;
1302                 }       
1303         }  /* RI*/
1304    }/* if num == 0*/
1305   } /* if the query was successful */
1306   
1307   return;
1308 } /* each_attribute_process() */
1309 
1310 
1311 
1312 /************************************************************
1313 * each_primary_key_select()                                 *
1314 *                                                           *
1315 * Function that forms a query for an object (w prinary keys)*
1316 * Called from g_slist_foreach() function.                   *
1317 * Primary keys are defined in Select[] array.               *
1318 *                                                           *
1319 * Returns: Nothing.                                         *
1320 *                                                           *
1321 *************************************************************/ 
1322 static void each_primary_key_select(void *element_data, void *result_ptr) 
     /* [<][>][^][v][top][bottom][index][help] */
1323 {
1324 Attribute_t *attr = element_data;
1325 Transaction_t *tr = (Transaction_t *)result_ptr;
1326 const char *query_fmt;
1327 unsigned int prefix, prefix_length;
1328 unsigned int begin_in, end_in;
1329 int begin_as, end_as;
1330 ip_prefix_t prefstr;
1331 ip_range_t  rangstr;
1332 ip_v6word_t i6_msb, i6_lsb;
1333 
1334    query_fmt = DF_get_select_query(attr->type);
1335 
1336   if (strcmp(query_fmt, "") != 0) {
1337     switch (DF_get_select_query_type(attr->type)) {
1338      case UD_MAIN_: 
1339                 g_string_sprintfa(tr->query, query_fmt, attr->value);
1340                 g_string_sprintfa(tr->K, attr->value);
1341                 break;
1342      case UD_MA_RT:
1343                 IP_pref_a2v4(attr->value, &prefstr, &prefix, &prefix_length);
1344                 g_string_sprintfa(tr->query, query_fmt, prefix, prefix_length);
1345                 g_string_sprintfa(tr->K, attr->value);
1346                 break;
1347      case UD_MA_IN:
1348                 IP_rang_a2v4(attr->value, &rangstr, &begin_in, &end_in);
1349                 g_string_sprintfa(tr->query, query_fmt, begin_in, end_in);
1350                 g_string_sprintfa(tr->K, attr->value);
1351                 break;
1352      case UD_MA_I6:
1353                 IP_pref_a2v6(attr->value, &prefstr, &i6_msb, &i6_lsb, &prefix_length);
1354                 g_string_sprintfa(tr->query, query_fmt, i6_msb, i6_lsb, prefix_length);
1355                 g_string_sprintfa(tr->K, attr->value);
1356                 break;                                          
1357      case UD_MA_AK:
1358                 convert_as_range(attr->value, &begin_as, &end_as);
1359                 g_string_sprintfa(tr->query, query_fmt, begin_as, end_as);
1360                 g_string_sprintfa(tr->K, attr->value);
1361                 break;
1362      default:
1363                 ER_perror(FAC_UD, UD_BUG, "query not defined for this type of attribute:[%d:%s]\n", attr->type, attr->value);
1364                 die;
1365 
1366         break;
1367     } 
1368   }
1369 } 
1370 
1371 /************************************************************
1372 * perform_create(const Object_t *obj, Transaction_t *tr)    * 
1373 *                                                           *
1374 * Procedure for creating a new object.                      *
1375 * First inserts object into 'last' table and gets object_id.*
1376 * Then processes all attributes.                            *
1377 *                                                           *
1378 * Returns: tr->succeeded: >0 success, 0 - error             *
1379 * Error code is stored in tr->error.                        *
1380 *                                                           *
1381 *************************************************************/ 
1382 static int perform_create(Transaction_t *tr) 
     /* [<][>][^][v][top][bottom][index][help] */
1383 {
1384  Object_t *obj;
1385  char *str;
1386  GString *query;
1387  long timestamp;
1388  int sql_err;
1389  long object_id;
1390   
1391   
1392  if ((query = g_string_sized_new(STR_XL)) == NULL){
1393   tr->succeeded=0;
1394   tr->error |= ERROR_U_MEM; 
1395   ER_perror(FAC_UD, UD_MEM, "cannot allocate gstring\n");
1396   die; 
1397  }
1398  
1399  
1400  obj=tr->object;
1401   
1402       str = (obj->object)->str;
1403       timestamp=time(NULL);
1404       tr->sequence_id=1; /* we start with 1*/
1405       /* Calculate the object_id - should be max+1 */
1406       tr->object_id = get_minmax_id(tr->sql_connection, "object_id", "last", 1);
1407       /* if last is empty, start with 1, otherwise the assign the next id */
1408       if(tr->object_id==-1)tr->object_id=1; else tr->object_id++;
1409       TR_update_id(tr);
1410 
1411       g_string_sprintf(query, "INSERT INTO last SET thread_id=%d, timestamp=%ld, sequence_id=1, object_type=%d, object='%s', pkey='%s' ",
1412                       tr->thread_ins, timestamp, tr->class_type, str, tr->K->str);
1413 
1414       ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s [%s]", UD_TAG, query->str);
1415       sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
1416 
1417      /* Check for affected rows. One row should be affected . */ 
1418       if (sql_err) {
1419         tr->error|=ERROR_U_DBS;
1420         tr->succeeded=0; 
1421         ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
1422         die;
1423       }
1424       else {
1425       /* Get generated (autoincrement) object_id */
1426         object_id=mysql_insert_id(tr->sql_connection);
1427         /* compare it with the calculated one */
1428         if(tr->object_id != object_id) die; /* probably implementation of autoincrement changed */
1429         g_slist_foreach(obj->attributes, each_attribute_process, tr);
1430       }
1431     g_string_free(query, TRUE);
1432     return(tr->succeeded);  
1433 } /* perform_create() */
1434 
1435 /************************************************************
1436 * perform_update(Transaction_t *tr)                         * 
1437 *                                                           *
1438 * Procedure for updating (existing) object.                 *
1439 * First processes all attributes.                           *
1440 * Then saves previous object in 'history' and updates       *
1441 * 'last' table.                                             *
1442 *                                                           *
1443 * Returns: tr->succeeded: >0 success, 0 - error             *
1444 * Error code is stored in tr->error.                        *
1445 *                                                           *
1446 *************************************************************/ 
1447 static int perform_update(Transaction_t *tr) 
     /* [<][>][^][v][top][bottom][index][help] */
1448 {
1449 Object_t *obj;
1450 char *str;
1451 GString *query;
1452 int num;
1453 long sequence_id;
1454 long timestamp;
1455 char *sq_error;
1456 int sql_err;
1457  
1458 
1459    obj=tr->object;
1460    /* get sequence number */
1461     
1462    sequence_id = get_sequence_id(tr);
1463    if(sequence_id==-1) {
1464       tr->error|=ERROR_U_DBS;
1465       tr->succeeded=0;
1466       ER_perror(FAC_UD, UD_SQL, "cannot get sequence_id");
1467       die;
1468    } 
1469    else tr->sequence_id=sequence_id; /* save it for rollback*/
1470    /* Update TR record */     
1471    TR_update_id(tr);
1472 
1473   /* process each attribute one by one */
1474   g_slist_foreach(obj->attributes, each_attribute_process, tr);
1475 
1476   /* If we've already failed or this is fast load - just return */
1477   if((tr->succeeded == 0) || (tr->load_pass != 0)) return(tr->succeeded);
1478   
1479     /* No return: thread_id=0 */
1480     /* Do it only if previous transactions finished well */
1481   if ((query = g_string_sized_new(STR_XL)) == NULL){
1482    tr->succeeded=0;
1483    tr->error |= ERROR_U_MEM; 
1484    ER_perror(FAC_UD, UD_MEM, "cannot allocate gstring");
1485    die; 
1486   }     
1487     /* copy object to the history table */
1488     g_string_sprintf(query,"INSERT history "
1489                   "SELECT %d, object_id, sequence_id, timestamp, object_type, object, pkey, serial, prev_serial "
1490                   "FROM last "
1491                   "WHERE object_id=%ld ", tr->thread_ins, tr->object_id);
1492 
1493     ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s [%s]", UD_TAG, query->str);
1494     sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
1495     
1496    /* Check for affected rows. One row should be affected . */
1497     num = mysql_affected_rows(tr->sql_connection);
1498     if (num < 1) {
1499          tr->error|=ERROR_U_DBS;
1500          tr->succeeded=0;
1501          if (sql_err) {
1502           sq_error=SQ_error(tr->sql_connection);
1503           ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
1504           die;
1505          }
1506          else {
1507           ER_perror(FAC_UD, UD_SQL, "0 rows affected [%s]\n", query->str);
1508         /* This is to check that this is really could happen */  
1509           die;
1510          } 
1511          g_string_free(query, TRUE);
1512          return(tr->succeeded);
1513     }
1514 
1515     /* Insert new version into the last */
1516     
1517     /* Put a timestamp */
1518     str = (obj->object)->str;
1519     timestamp=time(NULL);
1520 
1521 /* update last for commit/rollback */
1522                    
1523     g_string_sprintf(query, "INSERT last "
1524                    "SET thread_id=%d, object_id=%ld, sequence_id=%ld, timestamp=%ld, object_type=%d, object='%s', pkey='%s' ",
1525                    tr->thread_ins, tr->object_id, tr->sequence_id+1, timestamp, tr->class_type, str, tr->K->str);
1526 
1527 
1528     ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s [%s]", UD_TAG, query->str);
1529     sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
1530     
1531     /* Check for affected rows. One row should be affected */
1532     num = mysql_affected_rows(tr->sql_connection);
1533     if (num < 1) {
1534          tr->error|=ERROR_U_DBS;
1535          tr->succeeded=0;
1536          if(sql_err) {
1537           g_string_sprintfa(tr->error_script,"E[%d][:]:UPDATE last failed:%s\n" ,ERROR_U_DBS,SQ_error(tr->sql_connection));
1538           ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
1539           die;
1540          }
1541          else {
1542           ER_perror(FAC_UD, UD_SQL, "0 rows affected [%s]\n", query->str);
1543           /* This is to check that this is really could happen */  
1544           die;
1545          } 
1546          g_string_free(query, TRUE);
1547          return(tr->succeeded);
1548     }
1549  g_string_free(query, TRUE);
1550  return(tr->succeeded);   
1551 } /* perform_update() */
1552 
1553 
1554 
1555 
1556 /************************************************************
1557 * int object_process(Transaction_t *tr)                     *
1558 *                                                           *
1559 * This is the interface between core and upper layer        *
1560 * All it gets is Transaction *tr, which contains all        *
1561 * necessary information, including the object in its        *
1562 * internal representation.                                  *
1563 *                                                           *
1564 * Returns: tr->succeeded: >0 success, 0 - error             *
1565 * Error code is stored in tr->error.                        *
1566 *                                                           *
1567 *************************************************************/ 
1568 int object_process(Transaction_t *tr) 
     /* [<][>][^][v][top][bottom][index][help] */
1569 {
1570 int res;
1571 char nic[MAX_NH_LENGTH];
1572 int commit_now;
1573 
1574    /* for fast loader we do not perform commits/rollbacks */
1575    if(tr->load_pass == 0) commit_now = 0; else commit_now = 1;
1576    
1577    /* create and initialize TR record for crash recovery */
1578    TR_create_record(tr);
1579   
1580    if(ACT_DELETE(tr->action)){
1581                 ER_dbg_va(FAC_UD, ASP_UD_UPDLOG, "%s object: delete", UD_TAG);
1582                 /* check referential integrity of deletion */
1583                 UD_check_ref(tr);
1584                 /* for person & role - free the nic-handle in the NHR */
1585                 if(tr->succeeded && ((tr->class_type==C_PN) || (tr->class_type==C_RO)) && tr->nh ){
1586                  res = NH_free(tr->nh, tr->sql_connection, commit_now);
1587 
1588                  if(res == -1) { 
1589                    tr->succeeded=0; 
1590                    tr->error |= ERROR_U_DBS;
1591                    ER_perror(FAC_UD, UD_SQL, "cannot delete nic handle");
1592                    die;
1593                  }
1594                  else if(res == 0) { 
1595                    tr->succeeded=0; 
1596                    tr->error |= ERROR_U_OBJ;
1597                    ER_perror(FAC_UD, UD_SQL, "nic handle not found");
1598                    die;
1599                  }
1600                 }
1601                 /* if everything is Ok we are ready to commit */
1602                 if (tr->succeeded){
1603                  /* update object_id and sequence_id fields */
1604                  tr->sequence_id = get_sequence_id(tr);
1605                  TR_update_id(tr);
1606 
1607                  /* checkpoint the TR  - we are going to commit*/
1608                  CP_COMMIT(tr->action); TR_update_escript(tr); TR_update_status(tr);    
1609 
1610                  /* send an ack */      
1611                  UD_ack(tr);
1612 
1613                  /* delete the object and checkpoint it*/
1614                  UD_delete(tr);
1615                  UD_update_rx(tr, RX_OPER_DEL);
1616 
1617                  /* we need to update sequence_id because it was changed during update */
1618                  CP_DELETE_PASSED(tr->action); TR_update_id(tr); TR_update_status(tr);
1619 
1620                  /* Commit nic-handle deletion to the repository */
1621                  NH_commit(tr->sql_connection);
1622 
1623                  CP_COMMIT_NH_PASSED(tr->action); TR_update_status(tr);
1624 
1625                 }
1626                 else { /* just send an ack */
1627                  UD_ack(tr);
1628                 }
1629                 return(tr->succeeded); /*commit is not needed*/
1630     }
1631     else if(ACT_UPDATE(tr->action)){            
1632                 ER_dbg_va(FAC_UD, ASP_UD_UPDLOG, "%s object: update\n", UD_TAG);
1633                 perform_update(tr);
1634 
1635                 /* Commit nic-handle allocation (if any) to the repository if we are replacing dummy*/
1636                 if(ACT_UPD_NHR(tr->action) && tr->succeeded && ((tr->class_type==C_PN) || (tr->class_type==C_RO)) && tr->nh ){
1637                  /* convert nh to DB nIC handle before registration */
1638                  /* because there nh will bee freed */
1639                  NH_convert(nic, tr->nh);
1640 
1641                  res = NH_register(tr->nh, tr->sql_connection, commit_now);
1642 
1643                  if(res == -1) { 
1644                   tr->succeeded=0; 
1645                   tr->error |= ERROR_U_DBS;
1646                   ER_perror(FAC_UD, UD_SQL, "cannot allocate nic handle\n");
1647                   die;
1648                  }
1649                  else if(res == 0) { 
1650                   tr->succeeded=0; 
1651                   tr->error |= ERROR_U_OBJ;
1652                   ER_perror(FAC_UD, UD_SQL, "nic handle already in use\n");
1653                   die;
1654                  }
1655                  else { /* copy the NH to the report to return to DBupdate */
1656                  /* Convert nh to the database format */     
1657                   g_string_sprintfa(tr->error_script,"I[%d][%s]\n", A_NH, nic);
1658                  }               
1659                 }
1660     }
1661     else if(ACT_CREATE(tr->action)){
1662                 ER_dbg_va(FAC_UD, ASP_UD_OBJ, "%s object: create", UD_TAG);
1663                 perform_create(tr);
1664 
1665                 /* Commit nic-handle allocation (if any) to the repository */
1666                 if(tr->succeeded && ((tr->class_type==C_PN) || (tr->class_type==C_RO)) && tr->nh ){
1667                  /* convert nh to DB nIC handle before registration */
1668                  NH_convert(nic, tr->nh);
1669 
1670                  res = NH_register(tr->nh, tr->sql_connection, commit_now);
1671 
1672                  if(res == -1) { 
1673                   tr->succeeded=0; 
1674                   tr->error |= ERROR_U_DBS;
1675                   ER_perror(FAC_UD, UD_SQL, "cannot allocate nic handle");
1676                   die;
1677                  }
1678                  else if(res == 0) { 
1679                   tr->succeeded=0; 
1680                   tr->error |= ERROR_U_OBJ;
1681                   ER_inf_va(FAC_UD, ASP_UD_UPDLOG, "[%ld] object: nic handle %s already in use", tr->transaction_id, nic);
1682                   g_string_sprintfa(tr->error_script,"E[%d][nic handle %s already in use]\n", A_NH, nic);
1683                  }
1684                  else { /* copy the NH to the report to return to DBupdate */
1685                   g_string_sprintfa(tr->error_script,"I[%d][%s]\n", A_NH, nic);
1686                  }
1687                 }
1688         
1689      }
1690      else {
1691                 ER_inf_va(FAC_UD, ASP_UD_UPDLOG, "[%ld] object: unknown action", tr->transaction_id);
1692                 tr->succeeded=0;
1693                 tr->error|=ERROR_U_BADOP;
1694                 return(tr->succeeded);
1695      }          
1696 
1697    if(tr->load_pass == 0) { /* not for fast loader*/
1698       /* update object_id and sequence_id fields */
1699       TR_update_id(tr);
1700 
1701       if (tr->succeeded) {
1702 /*ER_dbg_va(FAC_UD, ASP_UD_OBJ, "%s Commit transaction\n", UD_TAG);      */
1703         /* checkpoint the TR  - we are going to commit*/
1704         CP_COMMIT(tr->action); TR_update_escript(tr); TR_update_status(tr);
1705 
1706         /* send an ack */       
1707         UD_ack(tr);
1708         /* commit the transaction and checkpoint it */
1709 
1710         UD_commit(tr);
1711         /* Commit nic-handle modifications to the repository */
1712 
1713         NH_commit(tr->sql_connection);
1714 
1715         CP_COMMIT_NH_PASSED(tr->action); TR_update_status(tr);
1716         /* TR will be marked as clean in UD_create_serial() */
1717       }
1718       else {
1719 /*ER_dbg_va(FAC_UD, ASP_UD_OBJ, "%s roll back transaction\n", UD_TAG);      */
1720         /* send an ack */       
1721         UD_ack(tr);
1722         UD_rollback(tr);
1723 
1724         CP_ROLLBACK_PASSED(tr->action); TR_update_status(tr);
1725         
1726         /* rollback nic-handle modifications to the repository */
1727         NH_rollback(tr->sql_connection);
1728 
1729         
1730         CP_ROLLBACK_NH_PASSED(tr->action); TR_update_status(tr);
1731         /* Delete TR record if in update mode. Next time (if any) DBupdate tries to submit, we'll start from scratch */
1732         /* In NRTM mode we create serial anyway, so the record will be deleted  */
1733         /* after serial is created TR record will be deleted in */
1734 
1735       }
1736     }  
1737  return(tr->succeeded);   
1738 } /* object_process() */
1739 

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