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