## 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] */