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.23 $
   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 long timestamp;
 398 
 399 char sobject_id[STR_M];
 400 char *sql_str;
 401 int sql_err;
 402 
 403  /* Try to allocate g_string. Return on error */        
 404  if ((query = g_string_sized_new(STR_XXL)) == NULL){ 
 405    ER_perror(FAC_UD, UD_MEM, "cannot allocate gstring\n");
 406    tr->succeeded=0;
 407    tr->error|=ERROR_U_MEM;
 408    die; 
 409  }
 410 
 411 
 412 /* Check for referential integrity of deletion */
 413 
 414    sprintf(sobject_id, "%ld", tr->object_id);
 415 
 416    switch(tr->class_type){
 417     case C_PN:
 418     case C_RO:
 419         
 420        /* Check that this person/role object is not referenced */
 421         
 422        for (i=0; t_ipn[i] != NULL; i++) { 
 423         /* Calculate number of references */
 424         sql_str= get_field_str(tr->sql_connection, "COUNT(*)", t_ipn[i], "pe_ro_id", sobject_id, NULL);
 425         if(sql_str) {
 426          num_rec = atol(sql_str);  free(sql_str);
 427          ref_id=tr->object_id;
 428          /* Check if it is a self reference (for role objects) */
 429          if(num_rec==1) {
 430           sql_str= get_field_str(tr->sql_connection, "object_id", t_ipn[i], "pe_ro_id", sobject_id, NULL);
 431           if(sql_str) {
 432            ref_id = atol(sql_str);  free(sql_str);
 433           } else {
 434            tr->succeeded=0; tr->error |= ERROR_U_DBS; break;
 435           }
 436          }
 437          /* If there are references (and not the only self reference) we cannot delete */
 438          if((num_rec>1) || (ref_id!=tr->object_id)) {
 439            g_string_sprintfa(tr->error_script,"E[%d][%ld]:ref integrity: %s\n" ,ERROR_U_OBJ, num_rec, t_ipn[i]);
 440            tr->succeeded=0; tr->error |= ERROR_U_OBJ;
 441          }
 442         } else {
 443         /* SQL error occured */
 444          tr->succeeded=0; tr->error |= ERROR_U_DBS;
 445          g_string_sprintfa(tr->error_script,"E[%d][%s]:%s\n", ERROR_U_DBS, t_ipn[i], SQ_error(tr->sql_connection));
 446         }
 447        }
 448        
 449        /* Check that this person/role object is not referenced by name (legacy stuff) */
 450        /* But allow overriding this check in NRTM mode and with override_integrity    */
 451        if(IS_DUMMY_ALLOWED(tr->mode))break;
 452         
 453        for (i=0; t_ipn[i] != NULL; i++) { 
 454         /* Calculate number of references */
 455         
 456         g_string_sprintf(query, "SELECT COUNT(*) FROM %s, person_role "
 457                                 "WHERE person_role.object_id=%s.pe_ro_id "
 458                                 "AND person_role.nic_hdl='%s' ", t_ipn[i], t_ipn[i], tr->save);
 459         
 460         sql_str= get_qresult_str(tr->sql_connection, query->str);
 461         if(sql_str) {
 462          num_rec = atol(sql_str);  free(sql_str);
 463          /* If there are references (no self reference is possible in this case) we cannot delete */
 464          if(num_rec>0) {
 465            g_string_sprintfa(tr->error_script,"E[%d][%ld]:ref integrity: %s\n" ,ERROR_U_OBJ, num_rec, t_ipn[i]);
 466            tr->succeeded=0; tr->error |= ERROR_U_OBJ;
 467          }
 468         } else {
 469         /* SQL error occured */
 470          tr->succeeded=0; tr->error |= ERROR_U_DBS;
 471          g_string_sprintfa(tr->error_script,"E[%d][%s]:%s\n", ERROR_U_DBS, t_ipn[i], SQ_error(tr->sql_connection));
 472         }
 473        }
 474           
 475        break;
 476         
 477     case C_MT:
 478     
 479         /* Check that this mntner object is not referenced */
 480         
 481        for (i=0; t_imt[i] != NULL; i++) { 
 482        /* Calculate number of references */
 483         sql_str= get_field_str(tr->sql_connection, "COUNT(*)", t_imt[i], "mnt_id", sobject_id, NULL);
 484         if(sql_str) {
 485          num_rec = atol(sql_str);  free(sql_str);
 486          ref_id=tr->object_id;
 487          /* Check if it is a self reference  */
 488          if(num_rec==1) { 
 489             sql_str= get_field_str(tr->sql_connection, "object_id", t_imt[i], "mnt_id", sobject_id, NULL);
 490             if(sql_str) {
 491               ref_id = atol(sql_str);  free(sql_str);
 492             } else {
 493               tr->succeeded=0; tr->error |= ERROR_U_DBS; break;
 494             } 
 495          }
 496          /* If there are references (and not the only self reference) we cannot delete */ 
 497          if((num_rec>1) || (ref_id!=tr->object_id)) {
 498            g_string_sprintfa(tr->error_script,"E[%d][%ld]:ref integrity: %s\n" ,ERROR_U_OBJ, num_rec, t_imt[i]);
 499            tr->succeeded=0; tr->error |= ERROR_U_OBJ;
 500          }
 501         } else {
 502          tr->succeeded=0; tr->error |= ERROR_U_DBS;
 503         }
 504        }   
 505        break;
 506         
 507     case C_RS:
 508     case C_AS:
 509         /* Check that this set object is not referenced */
 510         /* Calculate number of references */
 511         sql_str= get_field_str(tr->sql_connection, "COUNT(*)", "member_of", "set_id", sobject_id, NULL);
 512         if(sql_str) {
 513          num_rec = atol(sql_str);  free(sql_str);
 514          /* XXX though set may contain other sets as memebers, */
 515          /* there is no member-of attribute in these objects. */
 516          /* So no self-reference is possible */
 517          if(num_rec!=0) {
 518            g_string_sprintfa(tr->error_script,"E[%d][%ld]:ref integrity: %s\n" ,ERROR_U_OBJ, num_rec, "member_of");
 519            /*tr->succeeded=0; tr->error |= ERROR_U_OBJ;*/
 520           /* XXX Do not refuse the transaction but change the object to dummy */
 521           /* Update the history table */
 522                g_string_sprintf(query,  "INSERT history "
 523                                         "SELECT 0, object_id, sequence_id, timestamp, object_type, object, pkey, serial, prev_serial "
 524                                         "FROM last "
 525                                         "WHERE object_id=%ld ", tr->object_id);
 526 
 527       
 528                sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 529                if (sql_err) {
 530                 ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
 531                 tr->succeeded=0;
 532                 tr->error |=ERROR_U_DBS;
 533                 die;
 534                }
 535 
 536                /* insert new version into the last */
 537                timestamp=time(NULL);
 538               
 539               /* update the main table */
 540               g_string_sprintf(query, "UPDATE %s SET dummy=1 WHERE object_id=%ld ", DF_get_class_sql_table(tr->class_type), tr->object_id);
 541 
 542               sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 543               if (sql_err) {
 544                ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
 545                tr->succeeded=0;
 546                tr->error |= ERROR_U_DBS;
 547                die;
 548               }
 549  
 550               /* empty the contents, but leave in the table to prevent re-use of object_id */ 
 551               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);
 552 
 553               sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 554               if (sql_err) {
 555                ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
 556                tr->succeeded=0;
 557                tr->error |= ERROR_U_DBS;
 558                die;
 559               }
 560               return(0);
 561 
 562          }
 563         } else {
 564          tr->succeeded=0; tr->error |= ERROR_U_DBS;
 565         }
 566         break;
 567 
 568     default:
 569         break;    
 570    } 
 571    
 572  g_string_free(query, TRUE);
 573 
 574  /* Check if we have passed referential integrity check */  
 575  if(tr->succeeded) return(0); else return(-1);
 576  
 577 } 
 578         
 579 /************************************************************
 580 * int UD_delete()                                              *
 581 *                                                           *
 582 * Deletes the object                                        *
 583 *                                                           *
 584 * It deletes the object from all relevant tables. 
 585 * Then it updates the radix tree for routes, inetnums 
 586 * and rev.domains           *
 587 *                                                           *
 588 ************************************************************/
 589 int UD_delete(Transaction_t *tr) 
     /* [<][>][^][v][top][bottom][index][help] */
 590 {
 591 GString *query;
 592 int err=0;
 593 int i;
 594 long timestamp;
 595 int sql_err;
 596 
 597  /* Try to allocate g_string. Return on error */        
 598  if ((query = g_string_sized_new(STR_XXL)) == NULL){ 
 599    ER_perror(FAC_UD, UD_MEM, "cannot allocate gstring\n");
 600    tr->succeeded=0;
 601    tr->error|=ERROR_U_MEM;
 602    die; 
 603  }
 604 
 605   
 606 /* Lock all relevant tables */
 607    g_string_sprintf(query, "LOCK TABLES ");
 608    
 609    /* we need to lock tables for mntner and role differently, otherwise there will be duplicates (names names, etc.)*/
 610    if((tr->class_type!=C_MT) && (tr->class_type!=C_RO)){
 611     g_string_sprintfa(query, " %s WRITE,",  DF_get_class_sql_table(tr->class_type));
 612     
 613     for (i=0; tables[tr->class_type][i] != NULL; i++) 
 614       g_string_sprintfa(query, " %s WRITE,", tables[tr->class_type][i]);
 615    } else { /* mntner and role are special cases */
 616       g_string_sprintfa(query, " mntner WRITE, person_role WRITE, ");
 617    }
 618    
 619     for (i=TAB_START; tables[tr->class_type][i] != NULL; i++)
 620       g_string_sprintfa(query, " %s WRITE,", tables[tr->class_type][i]);
 621     
 622     g_string_sprintfa(query, " last WRITE, history WRITE ");
 623     
 624     sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 625     if (sql_err) {
 626          ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
 627          tr->succeeded=0;
 628          tr->error |=ERROR_U_DBS;
 629          die;
 630     }
 631 /* Update the history table */
 632 /* XXX Crash recovery: */
 633 /* If history was not updated - we will create a record */
 634 /* If history was already updated but last wasn't - we will just replace the record */
 635 /* If history and last were already updated - we will have an empty query - 0 rows should be affected */
 636     g_string_sprintf(query,     "REPLACE history "
 637                                 "SELECT 0, object_id, sequence_id, timestamp, object_type, object, pkey, serial, prev_serial "
 638                                 "FROM last "
 639                                 "WHERE object_id=%ld AND sequence_id=%ld ", tr->object_id, tr->sequence_id);
 640     sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 641     if (sql_err) {
 642          ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
 643          tr->succeeded=0;
 644          tr->error |=ERROR_U_DBS;
 645          die;
 646     }
 647 
 648 /* Delete records from the leaf and aux tables */
 649     for (i=TAB_START; tables[tr->class_type][i] != NULL; i++) {
 650      g_string_sprintf(query, "DELETE FROM %s WHERE object_id=%ld ", tables[tr->class_type][i], tr->object_id);
 651      sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 652     /*    ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s query (delete): %s\n", UD_TAG, query->str);*/
 653        if (sql_err) {
 654          ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
 655          tr->succeeded=0;
 656          tr->error |=ERROR_U_DBS;
 657          die;
 658        }
 659     }  
 660      
 661 
 662      
 663 /* Process the MAIN table  */
 664     g_string_sprintf(query, "DELETE FROM %s WHERE object_id=%ld ", DF_get_class_sql_table(tr->class_type), tr->object_id);
 665    
 666 
 667     sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 668     if (sql_err) {
 669          ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
 670          tr->succeeded=0;
 671          tr->error |=ERROR_U_DBS;
 672          die;
 673     }
 674 
 675        
 676   /* insert new version into the last */
 677   timestamp=time(NULL);
 678   
 679  /* empty the contents, but leave in the table to restrict re-use of object_id */ 
 680  /* XXX change sequence_id=0 so it is easy to say that the object was deleted */
 681   g_string_sprintf(query, "UPDATE last SET object='', timestamp=%ld, sequence_id=0  WHERE object_id=%ld ", timestamp, tr->object_id);
 682 
 683   sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 684   if (sql_err) {
 685          ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
 686          tr->succeeded=0;
 687          tr->error |= ERROR_U_DBS;
 688          die;
 689   }
 690 
 691 
 692 
 693  /* Unlock all tables */
 694   g_string_sprintf(query, "UNLOCK TABLES ");
 695   sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
 696   if (sql_err) {
 697         ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
 698         tr->succeeded=0;
 699         tr->error |= ERROR_U_DBS;
 700         die;
 701   }
 702 
 703 
 704   g_string_free(query, TRUE);
 705 
 706   return(err);
 707 
 708 } /* delete() */ 
 709 
 710 
 711 
 712                /* Do more in the forest
 713    * Update radix tree for route and inetnum
 714    */
 715 
 716 int UD_update_rx(Transaction_t *tr, rx_oper_mt mode)
     /* [<][>][^][v][top][bottom][index][help] */
 717 {
 718 rp_upd_pack_t *packptr = tr->packptr;
 719 int err=0;
 720 
 721   
 722   if(!IS_STANDALONE(tr->mode)) { /* only if server */
 723   
 724 
 725     /* Only for these types of objects and only if we have collected data (tr->save != NULL) */
 726     if( (   (tr->class_type==C_RT) 
 727          || (tr->class_type==C_IN) 
 728          || (tr->class_type==C_I6)
 729          || (tr->class_type==C_DN))) {
 730       /* Collect some data for radix tree and NH repository update for deletes*/
 731       if(mode == RX_OPER_DEL)g_slist_foreach((tr->object)->attributes, get_rx_data, tr);
 732       
 733       /* Except for regular domains we need to update radix tree */
 734       if(ACT_UPD_RX(tr->action)){
 735        packptr->key = tr->object_id;
 736        if( RP_pack_node(mode, packptr, tr->source_hdl) == RX_OK ) {
 737         err = 0;
 738        } else {
 739         err = (-1);
 740         ER_perror(FAC_UD, UD_BUG, "cannot update radix tree\n");
 741         die;
 742        }
 743       } /* update radix tree */
 744     }
 745   }
 746   return(err);
 747 }
 748    
 749                
 750 

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