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.25 $
   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                              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 #include "ud.h"
  34 #include "ud_int.h"
  35 #include "ud_comrol.h"
  36 #include "ud_tr.h"
  37 #include "rp.h"
  38 
  39 
  40 /************************************************************
  41 * int UD_rollback()                                         *
  42 *                                                           *
  43 * Rolls back the transaction                                *
  44 *                                                           *
  45 * It locks all relevant tables and processes the rollback   *
  46 * General approach is to delete all new records related     *
  47 * to the transaction (thread_id==thread_ins) and clean up   *
  48 * old ones (thread_id==thread_upd)                          *
  49 *                                                           *
  50 ************************************************************/
  51  
  52 int UD_rollback(Transaction_t *tr) {
     /* [<][>][^][v][top][bottom][index][help] */
  53 GString *query;
  54 int i, j;
  55 int sql_err;
  56 
  57  if(ACT_DELETE(tr->action)) return(0);
  58         
  59  if ((query = g_string_sized_new(STR_XXL)) == NULL){ 
  60    ER_perror(FAC_UD, UD_MEM, "cannot allocate gstring\n");
  61    tr->succeeded=0;
  62    tr->error |= ERROR_U_MEM;
  63    die; 
  64  }
  65 
  66 /* Lock all relevant tables */
  67    g_string_sprintf(query, "LOCK TABLES ");
  68    
  69    /* we need to lock tables for mntner and role differently, otherwise there will be duplicates (names names, etc.)*/
  70    if((tr->class_type!=C_MT) && (tr->class_type!=C_RO)){
  71     g_string_sprintfa(query, " %s WRITE,",  DF_get_class_sql_table(tr->class_type));
  72     
  73     for (i=0; tables[tr->class_type][i] != NULL; i++) 
  74       g_string_sprintfa(query, " %s WRITE,", tables[tr->class_type][i]);
  75    } else { /* mntner and role are special cases */
  76       g_string_sprintfa(query, " mntner WRITE, person_role WRITE, ");
  77    }
  78    
  79     for (i=TAB_START; tables[tr->class_type][i] != NULL; i++)
  80       g_string_sprintfa(query, " %s WRITE,", tables[tr->class_type][i]);
  81     
  82     g_string_sprintfa(query, " last WRITE, history WRITE ");
  83     
  84     sql_err=SQ_execute_query(tr->sql_connection, query->str, NULL);
  85 
  86 /* Process AUX and LEAF tables */
  87     for (i=TAB_START; tables[tr->class_type][i] != NULL; i++) {
  88     /* Delete what has been inserted */
  89     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);
  90     sql_err=SQ_execute_query(tr->sql_connection, query->str, NULL);
  91 
  92     /* Normalize what has been updated/touched */
  93     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);
  94     sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
  95   }
  96 
  97 /* Process MAIN tables */
  98 /* Delete if a record was created */
  99     g_string_sprintf(query, "DELETE FROM %s WHERE  object_id=%ld AND thread_id=%d", 
 100                              DF_get_class_sql_table(tr->class_type), tr->object_id, tr->thread_ins);
 101     sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 102     
 103     /* This is needed only for objects with possible dummy type, as they are updated with TR_UPDATE */
 104     /* We use this tag when committing the update to set dummy==0 */
 105     /* XXX may be later this should be reconsidered */
 106     g_string_sprintf(query, "UPDATE %s SET thread_id=0 WHERE  object_id=%ld AND thread_id=%d", 
 107                              DF_get_class_sql_table(tr->class_type), tr->object_id, tr->thread_upd);
 108     sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 109 
 110 /* Now tables  that might be affected by dummies */
 111     for(j=0; j < tr->ndummy; j++) 
 112     for (i=0; tables[tr->class_type][i] != NULL; i++) {
 113         g_string_sprintf(query, "DELETE FROM %s WHERE object_id=%ld ", tables[tr->class_type][i], tr->dummy_id[j]);
 114         sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 115     } 
 116 
 117   /* if dummies have been created - get rid of them */
 118   for(j=0; j < tr->ndummy; j++){
 119          g_string_sprintf(query, "DELETE FROM last WHERE object_id=%ld ", tr->dummy_id[j]);
 120          sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 121   }
 122   
 123 /* Rollback last and history tables */
 124 
 125     /* Delete what has been inserted */
 126     g_string_sprintf(query, "DELETE FROM history WHERE object_id=%ld AND thread_id=%d", tr->object_id, tr->thread_ins);
 127     sql_err=SQ_execute_query(tr->sql_connection, query->str, NULL);
 128 
 129     /* Normalize what has been updated/touched */
 130     g_string_sprintf(query, "UPDATE history 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, query->str, (SQ_result_set_t **)NULL);
 132 
 133     /* Delete what has been inserted */
 134     g_string_sprintf(query, "DELETE FROM last WHERE object_id=%ld AND thread_id=%d", tr->object_id, tr->thread_ins);
 135     sql_err=SQ_execute_query(tr->sql_connection, query->str, NULL);
 136 
 137     /* Normalize what has been updated/touched */
 138     g_string_sprintf(query, "UPDATE last SET thread_id=0 WHERE object_id=%ld AND thread_id=%d", tr->object_id, tr->thread_upd);
 139     sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 140 
 141   
 142   /* Unlock all tables */
 143   g_string_sprintf(query, "UNLOCK TABLES ");
 144   sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 145 
 146   
 147   g_string_free(query, TRUE);
 148   return(0);
 149 } /* rollback() */
 150 
 151 /************************************************************
 152 * int UD_commit_I()                                         *
 153 *                                                           *
 154 * Performs I phase of the commit - deletions                *
 155 *                                                           *
 156 * General approach is to delete untouched rec (thread_id==0)*
 157 *                                                           *
 158 ************************************************************/
 159 
 160 int UD_commit_I(Transaction_t *tr) {
     /* [<][>][^][v][top][bottom][index][help] */
 161 GString *query;
 162 int err=0;
 163 int i;
 164 int sql_err;
 165 
 166 
 167   if ((query = g_string_sized_new(STR_XXL)) == NULL){ 
 168    ER_perror(FAC_UD, UD_MEM, "cannot allocate gstring\n");
 169    tr->succeeded=0;
 170    tr->error|=ERROR_U_MEM;
 171    die; 
 172  }
 173 
 174 /* Commit the transaction for AUX and LEAF tables that may be affected (taken from object template) */
 175   for (i=TAB_START; tables[tr->class_type][i] != NULL; i++) {
 176  /* Delete old records from the tables */  
 177     g_string_sprintf(query, "DELETE FROM %s WHERE object_id=%ld AND thread_id=0 ", tables[tr->class_type][i], tr->object_id);
 178     sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 179     /*    ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s query (del old): %s\n", UD_TAG, query->str);  */
 180   }
 181 
 182  /* Delete old record from the last table */  
 183     g_string_sprintf(query, "DELETE FROM last WHERE object_id=%ld AND thread_id=0 ", tr->object_id);
 184     sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 185     /*    ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s query (del old): %s\n", UD_TAG, query->str);  */
 186 
 187   
 188  g_string_free(query, TRUE);
 189  return(err);   
 190 }
 191 
 192 /************************************************************
 193 * int UD_commit_II()                                        *
 194 *                                                           *
 195 * Performs I phase of the commit - deletions                *
 196 * General approach is to clean up all new and updated       *
 197 * records related to the transaction                        *
 198 * (thread_id==thread_ins) and (thread_id==thread_upd)       *
 199 *                                                           *
 200 ************************************************************/
 201 int UD_commit_II(Transaction_t *tr) {
     /* [<][>][^][v][top][bottom][index][help] */
 202 GString *query;
 203 int err=0;
 204 int i,j;
 205 A_Type_t attr_type;
 206 int sql_err;
 207 
 208  
 209  if ((query = g_string_sized_new(STR_XXL)) == NULL){ 
 210    ER_perror(FAC_UD, UD_MEM, "cannot allocate gstring\n");
 211    tr->succeeded=0;
 212    tr->error|=ERROR_U_MEM;
 213    die; 
 214  }
 215 
 216 
 217 /* Commit the transaction for AUX and LEAF tables that may be affected (taken from object template) */
 218   for (i=TAB_START; tables[tr->class_type][i] != NULL; i++) {
 219  /* Set thread_id to 0 to commit the transaction */    
 220     g_string_sprintf(query, "UPDATE %s SET thread_id=0 WHERE object_id=%ld", tables[tr->class_type][i], tr->object_id);
 221     sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 222     /*    ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s query (com new): %s\n", UD_TAG, query->str); */
 223   }
 224   
 225 /* Commit changes to the last table */  
 226    g_string_sprintf(query, "UPDATE last SET thread_id=0 WHERE object_id=%ld ", tr->object_id);
 227    sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 228 
 229 /* Commit changes to the history table */  
 230    g_string_sprintf(query, "UPDATE history SET thread_id=0 WHERE object_id=%ld ", tr->object_id);
 231    sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 232    
 233 /* Commit the transaction for the MAIN tables */
 234 
 235 /* Commit the transaction for person_role, mntner, as_set, route_set tables */
 236 /* They require different handling because of dummies */
 237 /* The rule is: Update: dummy->0, Insert: preserve dummy value */
 238 /* These tables do not require deletions since we cannot have such condition (object_id==0 AND thread_id==0) */
 239  if((tr->class_type==C_PN) || (tr->class_type==C_RO) || 
 240    (tr->class_type==C_AS) || (tr->class_type==C_RS) ||
 241    (tr->class_type==C_MT)){
 242 
 243  /* Process the rows updated/touched */
 244     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);
 245     sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 246  }
 247  
 248  switch (tr->class_type) {
 249    case C_IR:
 250    case C_IN:
 251    case C_I6:
 252    case C_FS: 
 253     if((tr->save)){ /* Some special processing for tables with the second attribute */
 254      /* Update the second field of the table with query like one below */
 255      /* UPDATE %s SET thread_id=%d, local_as='%s' WHERE object_id=%ld */
 256      
 257      switch(tr->class_type) {
 258       /* Local-as for inet-rtr */
 259       case C_IR: attr_type=A_LA;
 260                  break;
 261       /* netname for inetnum and inet6num */           
 262       case C_IN: 
 263       case C_I6: attr_type=A_NA;
 264                  break;
 265       /* filter for filter-set */           
 266       case C_FS: attr_type=A_FI;
 267                  break;
 268       default:
 269                  ER_perror(FAC_UD, UD_BUG, "not valid class type\n");
 270                  die;
 271                  break;           
 272      }
 273      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);
 274      sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 275     }
 276     else {
 277      ER_perror(FAC_UD, UD_BUG, "second attribute is not saved\n");
 278      die;
 279     }
 280     break;
 281    
 282    default:  
 283  /* Process all other MAIN tables for updates/inserts and person_role, mntner, as_set, route_set tables for rows inserts */
 284     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);
 285     sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 286     break;
 287  }  
 288 
 289 
 290 /* for tables that might be affected by dummies */
 291  for(j=0; j < tr->ndummy; j++)/* if dummies have been created */
 292    for (i=0; tables[tr->class_type][i] != NULL; i++) {
 293     g_string_sprintf(query, "UPDATE %s SET thread_id=0 WHERE object_id=%ld ", tables[tr->class_type][i], tr->dummy_id[j]);
 294     sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 295  }
 296 
 297 
 298    for(j=0; j < tr->ndummy; j++){/* if dummies have been created*/
 299          g_string_sprintf(query, "UPDATE last SET thread_id=0 WHERE object_id=%ld ", tr->dummy_id[j]);
 300          sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 301   }
 302  
 303  g_string_free(query, TRUE);
 304 
 305  return(err);           
 306 }
 307 
 308 
 309 /************************************************************
 310 * int UD_commit()                                           *
 311 *                                                           *
 312 * Commits the transaction                                   *
 313 *                                                           *
 314 * It locks all relevant tables and processes the 2 phases of*
 315 * commit. It also performs checkpointing of phases and      * 
 316 * radix tree update                                         * 
 317 *                                                           * 
 318 * We need to split commit into 2 because otherwise it is    *
 319 * hard to distinguish between commited records and untouched*
 320 * ones (both have thread_id==0). Splitting and checkpointing*
 321 * solves this problem                                       *
 322 *                                                           *
 323 ************************************************************/
 324 
 325 int UD_commit(Transaction_t *tr) {
     /* [<][>][^][v][top][bottom][index][help] */
 326 GString *query;
 327 int err=0;
 328 int i;
 329 int sql_err;
 330 
 331 if(ACT_DELETE(tr->action)) return(0);
 332 
 333  if ((query = g_string_sized_new(STR_XXL)) == NULL){ 
 334    ER_perror(FAC_UD, UD_MEM, "cannot allocate gstring\n");
 335    tr->succeeded=0;
 336    tr->error|=ERROR_U_MEM;
 337    die; 
 338  }
 339 
 340 /* Lock all relevant tables */
 341    g_string_sprintf(query, "LOCK TABLES ");
 342    
 343    /* we need to lock tables for mntner and role differently, otherwise there will be duplicates (names names, etc.)*/
 344    if((tr->class_type!=C_MT) && (tr->class_type!=C_RO)){
 345     g_string_sprintfa(query, " %s WRITE,",  DF_get_class_sql_table(tr->class_type));
 346     
 347     for (i=0; tables[tr->class_type][i] != NULL; i++) 
 348       g_string_sprintfa(query, " %s WRITE,", tables[tr->class_type][i]);
 349    } else { /* mntner and role are special cases */
 350       g_string_sprintfa(query, " mntner WRITE, person_role WRITE, ");
 351    }
 352    
 353     for (i=TAB_START; tables[tr->class_type][i] != NULL; i++)
 354       g_string_sprintfa(query, " %s WRITE,", tables[tr->class_type][i]);
 355     
 356     g_string_sprintfa(query, " last WRITE, history WRITE, transaction_rec WRITE ");
 357     
 358     sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 359 
 360 
 361   /* Perform first phase - deletions */
 362   UD_commit_I(tr);
 363   /* checkpoint this step */
 364   CP_COMMIT_I_PASSED(tr->action); TR_update_status(tr);
 365   /* Perform first phase - updates */
 366   UD_commit_II(tr);
 367   /* checkpoint this step */
 368   CP_COMMIT_II_PASSED(tr->action); TR_update_status(tr);
 369   
 370  /* Unlock all tables */
 371  g_string_sprintf(query, "UNLOCK TABLES ");
 372  sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 373 
 374  /* Update radix tree for route, inetnum and inaddr-arpa domain*/
 375  err = UD_update_rx(tr, RX_OPER_CRE);
 376  
 377  g_string_free(query, TRUE);
 378  return(err);
 379 } /* commit() */
 380 
 381 /************************************************************
 382 * int UD_check_ref()                                        *
 383 *                                                           *
 384 * Checks if the object to be deleted is referenced from     *
 385 * anywhere                                                  *
 386 *                                                           *
 387 * 0 - go ahead                                              *
 388 * -1 - deletion will compromise ref.integrity               *
 389 * Result is also reflected in tr->succeeded                 *
 390 ************************************************************/
 391 int UD_check_ref(Transaction_t *tr) 
     /* [<][>][^][v][top][bottom][index][help] */
 392 {
 393 GString *query;
 394 int i;
 395 long ref_id;
 396 long num_rec;
 397 
 398 char sobject_id[STR_M];
 399 char *sql_str;
 400 
 401  /* Try to allocate g_string. Return on error */        
 402  if ((query = g_string_sized_new(STR_XXL)) == NULL){ 
 403    ER_perror(FAC_UD, UD_MEM, "cannot allocate gstring\n");
 404    tr->succeeded=0;
 405    tr->error|=ERROR_U_MEM;
 406    die; 
 407  }
 408 
 409 
 410 /* Check for referential integrity of deletion */
 411 
 412    sprintf(sobject_id, "%ld", tr->object_id);
 413 
 414    switch(tr->class_type){
 415     case C_PN:
 416     case C_RO:
 417         
 418        /* Check that this person/role object is not referenced */
 419         
 420        for (i=0; t_ipn[i] != NULL; i++) { 
 421         /* Calculate number of references */
 422         sql_str= get_field_str(tr->sql_connection, "COUNT(*)", t_ipn[i], "pe_ro_id", sobject_id, NULL);
 423         if(sql_str) {
 424          num_rec = atol(sql_str);  free(sql_str);
 425          ref_id=tr->object_id;
 426          /* Check if it is a self reference (for role objects) */
 427          if(num_rec==1) {
 428           sql_str= get_field_str(tr->sql_connection, "object_id", t_ipn[i], "pe_ro_id", sobject_id, NULL);
 429           if(sql_str) {
 430            ref_id = atol(sql_str);  free(sql_str);
 431           } else {
 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);  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);  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);  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);  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] */