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

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