modules/ud/ud_comrol.c

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

FUNCTIONS

This source file includes following functions.
  1. UD_rollback
  2. UD_commit_I
  3. UD_commit_II
  4. UD_commit
  5. UD_check_ref
  6. UD_delete
  7. UD_update_rx

   1 /***************************************
   2   $Revision: 1.29 $
   3 
   4   rollback(), commit(), delete() - rollback, commit update transaction, delete an object
   5 
   6   Status: NOT REVUED, NOT TESTED
   7 
   8  Author(s):       Andrei Robachevsky
   9 
  10   ******************/ /******************
  11   Modification History:
  12         andrei (17/01/2000) Created.
  13   ******************/ /******************
  14   Copyright (c) 2000,2001                         RIPE NCC
  15  
  16   All Rights Reserved
  17   
  18   Permission to use, copy, modify, and distribute this software and its
  19   documentation for any purpose and without fee is hereby granted,
  20   provided that the above copyright notice appear in all copies and that
  21   both that copyright notice and this permission notice appear in
  22   supporting documentation, and that the name of the author not be
  23   used in advertising or publicity pertaining to distribution of the
  24   software without specific, written prior permission.
  25   
  26   THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  27   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
  28   AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
  29   DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
  30   AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  31   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  32  ***************************************/
  33 
  34 #include "rip.h"
  35 #include "ud_comrol.h"
  36 
  37 
  38 /************************************************************
  39 * int UD_rollback()                                         *
  40 *                                                           *
  41 * Rolls back the transaction                                *
  42 *                                                           *
  43 * It locks all relevant tables and processes the rollback   *
  44 * General approach is to delete all new records related     *
  45 * to the transaction (thread_id==thread_ins) and clean up   *
  46 * old ones (thread_id==thread_upd)                          *
  47 *                                                           *
  48 ************************************************************/
  49  
  50 int UD_rollback(Transaction_t *tr) {
     /* [<][>][^][v][top][bottom][index][help] */
  51 GString *query;
  52 int i, j;
  53 int sql_err;
  54 
  55  if(ACT_DELETE(tr->action)) return(0);
  56         
  57  if ((query = g_string_sized_new(STR_XXL)) == NULL){ 
  58    ER_perror(FAC_UD, UD_MEM, "cannot allocate gstring\n");
  59    tr->succeeded=0;
  60    tr->error |= ERROR_U_MEM;
  61    die; 
  62  }
  63 
  64 /* Lock all relevant tables */
  65    g_string_sprintf(query, "LOCK TABLES ");
  66    
  67    /* we need to lock tables for mntner and role differently, otherwise there will be duplicates (names names, etc.)*/
  68    if((tr->class_type!=C_MT) && (tr->class_type!=C_RO)){
  69     g_string_sprintfa(query, " %s WRITE,",  DF_get_class_sql_table(tr->class_type));
  70     
  71     for (i=0; tables[tr->class_type][i] != NULL; i++) 
  72       g_string_sprintfa(query, " %s WRITE,", tables[tr->class_type][i]);
  73    } else { /* mntner and role are special cases */
  74       g_string_sprintfa(query, " mntner WRITE, person_role WRITE, ");
  75    }
  76    
  77     for (i=TAB_START; tables[tr->class_type][i] != NULL; i++)
  78       g_string_sprintfa(query, " %s WRITE,", tables[tr->class_type][i]);
  79     
  80     g_string_sprintfa(query, " last WRITE, history WRITE ");
  81     
  82     sql_err=SQ_execute_query(tr->sql_connection, query->str, NULL);
  83 
  84 /* Process AUX and LEAF tables */
  85     for (i=TAB_START; tables[tr->class_type][i] != NULL; i++) {
  86     /* Delete what has been inserted */
  87     g_string_sprintf(query, "DELETE FROM %s WHERE object_id=%ld AND thread_id=%d", tables[tr->class_type][i], tr->object_id, tr->thread_ins);
  88     sql_err=SQ_execute_query(tr->sql_connection, query->str, NULL);
  89 
  90     /* Normalize what has been updated/touched */
  91     g_string_sprintf(query, "UPDATE %s SET thread_id=0 WHERE object_id=%ld AND thread_id=%d", tables[tr->class_type][i], tr->object_id, tr->thread_upd);
  92     sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
  93   }
  94 
  95 /* Process MAIN tables */
  96 /* Delete if a record was created */
  97     g_string_sprintf(query, "DELETE FROM %s WHERE  object_id=%ld AND thread_id=%d", 
  98                              DF_get_class_sql_table(tr->class_type), tr->object_id, tr->thread_ins);
  99     sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 100     
 101     /* This is needed only for objects with possible dummy type, as they are updated with TR_UPDATE */
 102     /* We use this tag when committing the update to set dummy==0 */
 103     /* XXX may be later this should be reconsidered */
 104     g_string_sprintf(query, "UPDATE %s SET thread_id=0 WHERE  object_id=%ld AND thread_id=%d", 
 105                              DF_get_class_sql_table(tr->class_type), tr->object_id, tr->thread_upd);
 106     sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 107 
 108 /* Now tables  that might be affected by dummies */
 109     for(j=0; j < tr->ndummy; j++) 
 110     for (i=0; tables[tr->class_type][i] != NULL; i++) {
 111         g_string_sprintf(query, "DELETE FROM %s WHERE object_id=%ld ", tables[tr->class_type][i], tr->dummy_id[j]);
 112         sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 113     } 
 114 
 115   /* if dummies have been created - get rid of them */
 116   for(j=0; j < tr->ndummy; j++){
 117          g_string_sprintf(query, "DELETE FROM last WHERE object_id=%ld ", tr->dummy_id[j]);
 118          sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 119   }
 120   
 121 /* Rollback last and history tables */
 122 
 123     /* Delete what has been inserted */
 124     g_string_sprintf(query, "DELETE FROM history WHERE object_id=%ld AND thread_id=%d", tr->object_id, tr->thread_ins);
 125     sql_err=SQ_execute_query(tr->sql_connection, query->str, NULL);
 126 
 127     /* Normalize what has been updated/touched */
 128     g_string_sprintf(query, "UPDATE history SET thread_id=0 WHERE object_id=%ld AND thread_id=%d", tr->object_id, tr->thread_upd);
 129     sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 130 
 131     /* Delete what has been inserted */
 132     g_string_sprintf(query, "DELETE FROM last WHERE object_id=%ld AND thread_id=%d", tr->object_id, tr->thread_ins);
 133     sql_err=SQ_execute_query(tr->sql_connection, query->str, NULL);
 134 
 135     /* Normalize what has been updated/touched */
 136     g_string_sprintf(query, "UPDATE last SET thread_id=0 WHERE object_id=%ld AND thread_id=%d", tr->object_id, tr->thread_upd);
 137     sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 138 
 139   
 140   /* Unlock all tables */
 141   g_string_sprintf(query, "UNLOCK TABLES ");
 142   sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 143 
 144   
 145   g_string_free(query, TRUE);
 146   return(0);
 147 } /* rollback() */
 148 
 149 /************************************************************
 150 * int UD_commit_I()                                         *
 151 *                                                           *
 152 * Performs I phase of the commit - deletions                *
 153 *                                                           *
 154 * General approach is to delete untouched rec (thread_id==0)*
 155 *                                                           *
 156 ************************************************************/
 157 
 158 int UD_commit_I(Transaction_t *tr) {
     /* [<][>][^][v][top][bottom][index][help] */
 159 GString *query;
 160 int err=0;
 161 int i;
 162 int sql_err;
 163 
 164 
 165   if ((query = g_string_sized_new(STR_XXL)) == NULL){ 
 166    ER_perror(FAC_UD, UD_MEM, "cannot allocate gstring\n");
 167    tr->succeeded=0;
 168    tr->error|=ERROR_U_MEM;
 169    die; 
 170  }
 171 
 172 /* Commit the transaction for AUX and LEAF tables that may be affected (taken from object template) */
 173   for (i=TAB_START; tables[tr->class_type][i] != NULL; i++) {
 174  /* Delete old records from the tables */  
 175     g_string_sprintf(query, "DELETE FROM %s WHERE object_id=%ld AND thread_id=0 ", tables[tr->class_type][i], tr->object_id);
 176     sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 177     /*    ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s query (del old): %s\n", UD_TAG, query->str);  */
 178   }
 179 
 180  /* Delete old record from the last table */  
 181     g_string_sprintf(query, "DELETE FROM last WHERE object_id=%ld AND thread_id=0 ", tr->object_id);
 182     sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 183     /*    ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s query (del old): %s\n", UD_TAG, query->str);  */
 184 
 185   
 186  g_string_free(query, TRUE);
 187  return(err);   
 188 }
 189 
 190 /************************************************************
 191 * int UD_commit_II()                                        *
 192 *                                                           *
 193 * Performs I phase of the commit - deletions                *
 194 * General approach is to clean up all new and updated       *
 195 * records related to the transaction                        *
 196 * (thread_id==thread_ins) and (thread_id==thread_upd)       *
 197 *                                                           *
 198 ************************************************************/
 199 int UD_commit_II(Transaction_t *tr) {
     /* [<][>][^][v][top][bottom][index][help] */
 200 GString *query;
 201 int err=0;
 202 int i,j;
 203 A_Type_t attr_type;
 204 int sql_err;
 205 
 206  
 207  if ((query = g_string_sized_new(STR_XXL)) == NULL){ 
 208    ER_perror(FAC_UD, UD_MEM, "cannot allocate gstring\n");
 209    tr->succeeded=0;
 210    tr->error|=ERROR_U_MEM;
 211    die; 
 212  }
 213 
 214 
 215 /* Commit the transaction for AUX and LEAF tables that may be affected (taken from object template) */
 216   for (i=TAB_START; tables[tr->class_type][i] != NULL; i++) {
 217  /* Set thread_id to 0 to commit the transaction */    
 218     g_string_sprintf(query, "UPDATE %s SET thread_id=0 WHERE object_id=%ld", tables[tr->class_type][i], tr->object_id);
 219     sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 220     /*    ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s query (com new): %s\n", UD_TAG, query->str); */
 221   }
 222   
 223 /* Commit changes to the last table */  
 224    g_string_sprintf(query, "UPDATE last SET thread_id=0 WHERE object_id=%ld ", tr->object_id);
 225    sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 226 
 227 /* Commit changes to the history table */  
 228    g_string_sprintf(query, "UPDATE history SET thread_id=0 WHERE object_id=%ld ", tr->object_id);
 229    sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 230    
 231 /* Commit the transaction for the MAIN tables */
 232 
 233 /* Commit the transaction for person_role, mntner, as_set, route_set tables */
 234 /* They require different handling because of dummies */
 235 /* The rule is: Update: dummy->0, Insert: preserve dummy value */
 236 /* These tables do not require deletions since we cannot have such condition (object_id==0 AND thread_id==0) */
 237  if((tr->class_type==C_PN) || (tr->class_type==C_RO) || 
 238    (tr->class_type==C_AS) || (tr->class_type==C_RS) ||
 239    (tr->class_type==C_MT)){
 240 
 241  /* Process the rows updated/touched */
 242     g_string_sprintf(query, "UPDATE %s SET thread_id=0, dummy=0 WHERE object_id=%ld AND thread_id=%d ",  DF_get_class_sql_table(tr->class_type), tr->object_id, tr->thread_upd);
 243     sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 244  }
 245  
 246  switch (tr->class_type) {
 247    case C_IR:
 248    case C_IN:
 249    case C_I6:
 250    case C_FS: 
 251     if((tr->save)){ /* Some special processing for tables with the second attribute */
 252      /* Update the second field of the table with query like one below */
 253      /* UPDATE %s SET thread_id=%d, local_as='%s' WHERE object_id=%ld */
 254      
 255      switch(tr->class_type) {
 256       /* Local-as for inet-rtr */
 257       case C_IR: attr_type=A_LA;
 258                  break;
 259       /* netname for inetnum and inet6num */           
 260       case C_IN: 
 261       case C_I6: attr_type=A_NA;
 262                  break;
 263       /* filter for filter-set */           
 264       case C_FS: attr_type=A_FI;
 265                  break;
 266       default:
 267                  ER_perror(FAC_UD, UD_BUG, "not valid class type\n");
 268                  attr_type=A_END;
 269                  die;
 270      }
 271      g_string_sprintf(query, DF_get_update_query(attr_type), DF_get_class_sql_table(tr->class_type), 0, (char *)tr->save, tr->object_id);
 272      sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 273     }
 274     else {
 275      ER_perror(FAC_UD, UD_BUG, "second attribute is not saved\n");
 276      die;
 277     }
 278     break;
 279    
 280    default:  
 281  /* Process all other MAIN tables for updates/inserts and person_role, mntner, as_set, route_set tables for rows inserts */
 282     g_string_sprintf(query, "UPDATE %s SET thread_id=0 WHERE object_id=%ld AND thread_id>0", DF_get_class_sql_table(tr->class_type), tr->object_id);
 283     sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 284     break;
 285  }  
 286 
 287 
 288 /* for tables that might be affected by dummies */
 289  for(j=0; j < tr->ndummy; j++)/* if dummies have been created */
 290    for (i=0; tables[tr->class_type][i] != NULL; i++) {
 291     g_string_sprintf(query, "UPDATE %s SET thread_id=0 WHERE object_id=%ld ", tables[tr->class_type][i], tr->dummy_id[j]);
 292     sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 293  }
 294 
 295 
 296    for(j=0; j < tr->ndummy; j++){/* if dummies have been created*/
 297          g_string_sprintf(query, "UPDATE last SET thread_id=0 WHERE object_id=%ld ", tr->dummy_id[j]);
 298          sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 299   }
 300  
 301  g_string_free(query, TRUE);
 302 
 303  return(err);           
 304 }
 305 
 306 
 307 /************************************************************
 308 * int UD_commit()                                           *
 309 *                                                           *
 310 * Commits the transaction                                   *
 311 *                                                           *
 312 * It locks all relevant tables and processes the 2 phases of*
 313 * commit. It also performs checkpointing of phases and      * 
 314 * radix tree update                                         * 
 315 *                                                           * 
 316 * We need to split commit into 2 because otherwise it is    *
 317 * hard to distinguish between commited records and untouched*
 318 * ones (both have thread_id==0). Splitting and checkpointing*
 319 * solves this problem                                       *
 320 *                                                           *
 321 ************************************************************/
 322 
 323 int UD_commit(Transaction_t *tr) {
     /* [<][>][^][v][top][bottom][index][help] */
 324 GString *query;
 325 int err=0;
 326 int i;
 327 int sql_err;
 328 
 329 if(ACT_DELETE(tr->action)) return(0);
 330 
 331  if ((query = g_string_sized_new(STR_XXL)) == NULL){ 
 332    ER_perror(FAC_UD, UD_MEM, "cannot allocate gstring\n");
 333    tr->succeeded=0;
 334    tr->error|=ERROR_U_MEM;
 335    die; 
 336  }
 337 
 338 /* Lock all relevant tables */
 339    g_string_sprintf(query, "LOCK TABLES ");
 340    
 341    /* we need to lock tables for mntner and role differently, otherwise there will be duplicates (names names, etc.)*/
 342 /*   if((tr->class_type!=C_MT) && (tr->class_type!=C_RO)){ */
 343    g_string_sprintfa(query, " %s WRITE,",  DF_get_class_sql_table(tr->class_type));
 344    
 345    if((tr->class_type==C_RO)) g_string_sprintfa(query, " mntner WRITE, ");
 346    else if((tr->class_type==C_MT)) g_string_sprintfa(query, " person_role WRITE, names WRITE, "); 
 347     else
 348      for (i=0; tables[tr->class_type][i] != NULL; i++) 
 349         g_string_sprintfa(query, " %s WRITE,", tables[tr->class_type][i]);
 350    
 351    for (i=TAB_START; tables[tr->class_type][i] != NULL; i++)
 352       g_string_sprintfa(query, " %s WRITE,", tables[tr->class_type][i]);
 353     
 354    g_string_sprintfa(query, " last WRITE, history WRITE, transaction_rec WRITE ");
 355     
 356    sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 357 
 358 
 359   /* Perform first phase - deletions */
 360   UD_commit_I(tr);
 361   /* checkpoint this step */
 362   CP_COMMIT_I_PASSED(tr->action); TR_update_status(tr);
 363   /* Perform first phase - updates */
 364   UD_commit_II(tr);
 365   /* checkpoint this step */
 366   CP_COMMIT_II_PASSED(tr->action); TR_update_status(tr);
 367   
 368  /* Unlock all tables */
 369  g_string_sprintf(query, "UNLOCK TABLES ");
 370  sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 371 
 372  /* Update radix tree for route, inetnum and inaddr-arpa domain*/
 373  err = UD_update_rx(tr, RX_OPER_CRE);
 374  
 375  g_string_free(query, TRUE);
 376  return(err);
 377 } /* commit() */
 378 
 379 /************************************************************
 380 * int UD_check_ref()                                        *
 381 *                                                           *
 382 * Checks if the object to be deleted is referenced from     *
 383 * anywhere                                                  *
 384 *                                                           *
 385 * 0 - go ahead                                              *
 386 * -1 - deletion will compromise ref.integrity               *
 387 * Result is also reflected in tr->succeeded                 *
 388 ************************************************************/
 389 int UD_check_ref(Transaction_t *tr) 
     /* [<][>][^][v][top][bottom][index][help] */
 390 {
 391 GString *query;
 392 int i;
 393 long ref_id;
 394 long num_rec;
 395 
 396 char sobject_id[STR_M];
 397 char *sql_str;
 398 
 399  /* Try to allocate g_string. Return on error */        
 400  if ((query = g_string_sized_new(STR_XXL)) == NULL){ 
 401    ER_perror(FAC_UD, UD_MEM, "cannot allocate gstring\n");
 402    tr->succeeded=0;
 403    tr->error|=ERROR_U_MEM;
 404    die; 
 405  }
 406 
 407 
 408 /* Check for referential integrity of deletion */
 409 
 410    sprintf(sobject_id, "%ld", tr->object_id);
 411 
 412    switch(tr->class_type){
 413     case C_PN:
 414     case C_RO:
 415         
 416        /* Check that this person/role object is not referenced */
 417         
 418        for (i=0; t_ipn[i] != NULL; i++) { 
 419         /* Calculate number of references */
 420         sql_str= get_field_str(tr->sql_connection, "COUNT(*)", t_ipn[i], "pe_ro_id", sobject_id, NULL);
 421         if(sql_str) {
 422          num_rec = atol(sql_str);  UT_free(sql_str);
 423          ref_id=tr->object_id;
 424          /* Check if it is a self reference (for role objects) */
 425          if(num_rec==1) {
 426           sql_str= get_field_str(tr->sql_connection, "object_id", t_ipn[i], "pe_ro_id", sobject_id, NULL);
 427           if(sql_str) {
 428            ref_id = atol(sql_str);  UT_free(sql_str);
 429           } else {
 430            /* this is not possible unless it is an sql error */
 431            /*XXX probably we need to die */       
 432            tr->succeeded=0; tr->error |= ERROR_U_DBS; break;
 433           }
 434          }
 435          /* If there are references (and not the only self reference) we cannot delete */
 436          if((num_rec>1) || (ref_id!=tr->object_id)) {
 437            g_string_sprintfa(tr->error_script,"E[%d][%ld]:ref integrity: %s\n" ,ERROR_U_OBJ, num_rec, t_ipn[i]);
 438            tr->succeeded=0; tr->error |= ERROR_U_OBJ;
 439          }
 440         } else {
 441         /* SQL error occured */
 442          tr->succeeded=0; tr->error |= ERROR_U_DBS;
 443          g_string_sprintfa(tr->error_script,"E[%d][%s]:%s\n", ERROR_U_DBS, t_ipn[i], SQ_error(tr->sql_connection));
 444         }
 445        }
 446        
 447        /* Check that this person/role object is not referenced by name (legacy stuff) */
 448        /* But allow overriding this check in NRTM mode and with override_integrity    */
 449        if(IS_DUMMY_ALLOWED(tr->mode))break;
 450         
 451        for (i=0; t_ipn[i] != NULL; i++) { 
 452         /* Calculate number of references */
 453         
 454         g_string_sprintf(query, "SELECT COUNT(*) FROM %s, person_role "
 455                                 "WHERE person_role.object_id=%s.pe_ro_id "
 456                                 "AND person_role.nic_hdl='%s' ", t_ipn[i], t_ipn[i], tr->save);
 457         
 458         sql_str= get_qresult_str(tr->sql_connection, query->str);
 459         if(sql_str) {
 460          num_rec = atol(sql_str);  UT_free(sql_str);
 461          /* If there are references (no self reference is possible in this case) we cannot delete */
 462          if(num_rec>0) {
 463            g_string_sprintfa(tr->error_script,"E[%d][%ld]:ref integrity: %s\n" ,ERROR_U_OBJ, num_rec, t_ipn[i]);
 464            tr->succeeded=0; tr->error |= ERROR_U_OBJ;
 465          }
 466         } else {
 467         /* SQL error occured */
 468          tr->succeeded=0; tr->error |= ERROR_U_DBS;
 469          g_string_sprintfa(tr->error_script,"E[%d][%s]:%s\n", ERROR_U_DBS, t_ipn[i], SQ_error(tr->sql_connection));
 470         }
 471        }
 472           
 473        break;
 474         
 475     case C_MT:
 476     
 477         /* Check that this mntner object is not referenced */
 478         
 479        for (i=0; t_imt[i] != NULL; i++) { 
 480        /* Calculate number of references */
 481         sql_str= get_field_str(tr->sql_connection, "COUNT(*)", t_imt[i], "mnt_id", sobject_id, NULL);
 482         if(sql_str) {
 483          num_rec = atol(sql_str);  UT_free(sql_str);
 484          ref_id=tr->object_id;
 485          /* Check if it is a self reference  */
 486          if(num_rec==1) { 
 487             sql_str= get_field_str(tr->sql_connection, "object_id", t_imt[i], "mnt_id", sobject_id, NULL);
 488             if(sql_str) {
 489               ref_id = atol(sql_str);  UT_free(sql_str);
 490             } else {
 491               tr->succeeded=0; tr->error |= ERROR_U_DBS; break;
 492             } 
 493          }
 494          /* If there are references (and not the only self reference) we cannot delete */ 
 495          if((num_rec>1) || (ref_id!=tr->object_id)) {
 496            g_string_sprintfa(tr->error_script,"E[%d][%ld]:ref integrity: %s\n" ,ERROR_U_OBJ, num_rec, t_imt[i]);
 497            tr->succeeded=0; tr->error |= ERROR_U_OBJ;
 498          }
 499         } else {
 500          tr->succeeded=0; tr->error |= ERROR_U_DBS;
 501         }
 502        }   
 503        break;
 504         
 505     case C_RS:
 506     case C_AS:
 507         /* Check that this set object is not referenced */
 508         /* Calculate number of references */
 509         sql_str= get_field_str(tr->sql_connection, "COUNT(*)", "member_of", "set_id", sobject_id, NULL);
 510         if(sql_str) {
 511          num_rec = atol(sql_str);  UT_free(sql_str);
 512          /* XXX though set may contain other sets as memebers, */
 513          /* there is no member-of attribute in these objects. */
 514          /* So no self-reference is possible */
 515          if(num_rec!=0) {
 516            g_string_sprintfa(tr->error_script,"I[%d][%ld]:ref integrity: %s\n" ,ERROR_U_OBJ, num_rec, "member_of");
 517           /* XXX Do not refuse the transaction but change the object to dummy */
 518            tr->action |=TA_DUMMY;
 519          }
 520         } else {
 521          tr->succeeded=0; tr->error |= ERROR_U_DBS;
 522         }
 523         break;
 524 
 525     default:
 526         break;    
 527    } 
 528    
 529  g_string_free(query, TRUE);
 530 
 531  /* Check if we have passed referential integrity check */  
 532  if(tr->succeeded) return(0); else return(-1);
 533  
 534 } 
 535         
 536 /************************************************************
 537 * int UD_delete()                                              *
 538 *                                                           *
 539 * Deletes the object                                        *
 540 *                                                           *
 541 * It deletes the object from all relevant tables. 
 542 * Then it updates the radix tree for routes, inetnums 
 543 * and rev.domains           *
 544 *                                                           *
 545 ************************************************************/
 546 int UD_delete(Transaction_t *tr) 
     /* [<][>][^][v][top][bottom][index][help] */
 547 {
 548 GString *query;
 549 int err=0;
 550 int i;
 551 long timestamp;
 552 int sql_err;
 553 int ref_set;
 554 
 555 /* if we are deliting referenced set, we need to  perform delete a bit differently */
 556 /* no deletions of aux tables */
 557 /* dummy main, instead of del */
 558 /* dummy last instead of empty */
 559 /* So let's determine if we are deliting referenced set */
 560 if ((tr->class_type==C_AS || tr->class_type==C_RS) && ACT_UPD_DUMMY(tr->action)) ref_set = 1; else ref_set = 0;
 561 
 562  /* Try to allocate g_string. Return on error */        
 563  if ((query = g_string_sized_new(STR_XXL)) == NULL){ 
 564    ER_perror(FAC_UD, UD_MEM, "cannot allocate gstring\n");
 565    tr->succeeded=0;
 566    tr->error|=ERROR_U_MEM;
 567    die; 
 568  }
 569 
 570   
 571 /* Lock all relevant tables */
 572    g_string_sprintf(query, "LOCK TABLES ");
 573    
 574    /* we need to lock tables for mntner and role differently, otherwise there will be duplicates (names names, etc.)*/
 575    if((tr->class_type!=C_MT) && (tr->class_type!=C_RO)){
 576     g_string_sprintfa(query, " %s WRITE,",  DF_get_class_sql_table(tr->class_type));
 577     
 578     for (i=0; tables[tr->class_type][i] != NULL; i++) 
 579       g_string_sprintfa(query, " %s WRITE,", tables[tr->class_type][i]);
 580    } else { /* mntner and role are special cases */
 581       g_string_sprintfa(query, " mntner WRITE, person_role WRITE, ");
 582    }
 583    
 584     for (i=TAB_START; tables[tr->class_type][i] != NULL; i++)
 585       g_string_sprintfa(query, " %s WRITE,", tables[tr->class_type][i]);
 586     
 587     g_string_sprintfa(query, " last WRITE, history WRITE ");
 588     
 589     sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 590     if (sql_err) {
 591          ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
 592          tr->succeeded=0;
 593          tr->error |=ERROR_U_DBS;
 594          die;
 595     }
 596 /* Update the history table */
 597 /* XXX Crash recovery: */
 598 /* If history was not updated - we will create a record */
 599 /* If history was already updated but last wasn't - we will just replace the record */
 600 /* If history and last were already updated - we will have an empty query - 0 rows should be affected */
 601     g_string_sprintf(query,     "REPLACE history "
 602                                 "SELECT 0, object_id, sequence_id, timestamp, object_type, object, pkey, serial, prev_serial "
 603                                 "FROM last "
 604                                 "WHERE object_id=%ld AND sequence_id=%ld ", tr->object_id, tr->sequence_id);
 605     sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 606     if (sql_err) {
 607          ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
 608          tr->succeeded=0;
 609          tr->error |=ERROR_U_DBS;
 610          die;
 611     }
 612 
 613 /* Delete records from the leaf and aux tables */
 614     for (i=TAB_START; tables[tr->class_type][i] != NULL; i++) {
 615      g_string_sprintf(query, "DELETE FROM %s WHERE object_id=%ld ", tables[tr->class_type][i], tr->object_id);
 616      sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 617     /*    ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s query (delete): %s\n", UD_TAG, query->str);*/
 618        if (sql_err) {
 619          ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
 620          tr->succeeded=0;
 621          tr->error |=ERROR_U_DBS;
 622          die;
 623        }
 624     }  
 625      
 626 
 627  /* For all object except as-sets and route-sets we need to empty MAIN table */
 628  /* For referenced sets, however, we transform them to dummy, not delete */
 629  if (ref_set == 0) {
 630 
 631 /* Process the MAIN table  */
 632     g_string_sprintf(query, "DELETE FROM %s WHERE object_id=%ld ", DF_get_class_sql_table(tr->class_type), tr->object_id);
 633    
 634 
 635     sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 636     if (sql_err) {
 637          ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
 638          tr->succeeded=0;
 639          tr->error |=ERROR_U_DBS;
 640          die;
 641     }
 642  
 643  } else { /* this is the referenced set */
 644  /* we need to 'dummy' MAIN */
 645     g_string_sprintf(query, "UPDATE %s SET dummy=1 WHERE object_id=%ld ", DF_get_class_sql_table(tr->class_type), tr->object_id);
 646                
 647     sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 648     if (sql_err) {
 649          ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
 650          tr->succeeded=0;
 651          tr->error |= ERROR_U_DBS;
 652          die;
 653     }
 654  }
 655        
 656   /* insert new version into the last */
 657   timestamp=time(NULL);
 658   
 659  if(ref_set == 0) 
 660  {
 661  /* empty the contents, but leave in the table to restrict re-use of object_id */ 
 662  /* XXX change sequence_id=0 so it is easy to say that the object was deleted */
 663   g_string_sprintf(query, "UPDATE last SET object='', timestamp=%ld, sequence_id=0  WHERE object_id=%ld ", timestamp, tr->object_id);
 664 
 665   sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 666   if (sql_err) {
 667          ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
 668          tr->succeeded=0;
 669          tr->error |= ERROR_U_DBS;
 670          die;
 671   }
 672  } else {/* this is the referenced set */
 673  /* 'dummy' the contents, but leave in the table to prevent re-use of object_id */ 
 674  g_string_sprintf(query, "UPDATE last SET object='DUMMY SET', object_type=%d, sequence_id=%ld, timestamp=%ld  WHERE object_id=%ld ", DUMMY_TYPE, tr->sequence_id+1, timestamp, tr->object_id);
 675 
 676  sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 677  if (sql_err) {
 678      ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
 679      tr->succeeded=0;
 680      tr->error |= ERROR_U_DBS;
 681     die;
 682    }
 683  }
 684 
 685 
 686  /* Unlock all tables */
 687   g_string_sprintf(query, "UNLOCK TABLES ");
 688   sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 689   if (sql_err) {
 690         ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
 691         tr->succeeded=0;
 692         tr->error |= ERROR_U_DBS;
 693         die;
 694   }
 695 
 696 
 697   g_string_free(query, TRUE);
 698 
 699   return(err);
 700 
 701 } /* delete() */ 
 702 
 703 
 704 
 705                /* Do more in the forest
 706    * Update radix tree for route and inetnum
 707    */
 708 
 709 int UD_update_rx(Transaction_t *tr, rx_oper_mt mode)
     /* [<][>][^][v][top][bottom][index][help] */
 710 {
 711 rp_upd_pack_t *packptr = tr->packptr;
 712 int err=0;
 713 
 714   
 715   if(!IS_STANDALONE(tr->mode)) { /* only if server */
 716   
 717 
 718     /* Only for these types of objects and only if we have collected data (tr->save != NULL) */
 719     if( (   (tr->class_type==C_RT) 
 720          || (tr->class_type==C_IN) 
 721          || (tr->class_type==C_I6)
 722          || (tr->class_type==C_DN))) {
 723       /* Collect some data for radix tree and NH repository update for deletes*/
 724       if(mode == RX_OPER_DEL)g_slist_foreach((tr->object)->attributes, get_rx_data, tr);
 725       
 726       /* Except for regular domains we need to update radix tree */
 727       if(ACT_UPD_RX(tr->action)){
 728        packptr->key = tr->object_id;
 729        if( RP_pack_node(mode, packptr, tr->source_hdl) == RX_OK ) {
 730         err = 0;
 731        } else {
 732         err = (-1);
 733         ER_perror(FAC_UD, UD_BUG, "cannot update radix tree\n");
 734         die;
 735        }
 736       } /* update radix tree */
 737     }
 738   }
 739   return(err);
 740 }
 741    
 742                
 743 

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