modules/ud/ud_comrol.c

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

DEFINITIONS

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

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