Source File modules/ud/ud_comrol.c

    1    | /***************************************
    2    |   $Revision: 1.17 $
    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 "rp.h"
    37   |
    38   | /************************************************************
    39   | * int rollback()                                            *
    40   | *                                                           *
    41   | * Rolls back the transaction                                *
    42   | *                                                           *
    43   | * It locks all relevant tables and processes the rollback   *
    44   | * General approach is to delete all new records related     *
    45   | * to the transaction (thread_id==thread_ins) and clean up   *
    46   | * old ones (thread_id==thread_upd)                          *
    47   | *                                                           *
    48   | ************************************************************/
    49   |
    50   | int rollback(Transaction_t *tr) {
    51   | GString *query;
    52   | long sequence_id;
    53   | int i, j;
    54   | int sql_err;
    55   |
    56   |  if(ACT_DELETE(tr->action)) return(0);
    57   |
    58   |  if ((query = g_string_sized_new(STR_XXL)) == NULL){
    59   |    fprintf(stderr, "E: cannot allocate gstring\n");
    60   |    tr->succeeded=0;
    61   |    tr->error |= ERROR_U_MEM;
    62   |    return(ERROR_U_MEM); }
    63   |
    64   | /* Lock all relevant tables */
    65   |    g_string_sprintf(query, "LOCK TABLES %s WRITE,",  DF_get_class_sql_table(tr->class_type));
    66   |
    67   |     for (i=0; tables[tr->class_type][i] != NULL; i++)
    68   |       g_string_sprintfa(query, " %s WRITE,", tables[tr->class_type][i]);
    69   |
    70   |     for (i=TAB_START; tables[tr->class_type][i] != NULL; i++)
    71   |       g_string_sprintfa(query, " %s WRITE,", tables[tr->class_type][i]);
    72   |
    73   |     g_string_sprintfa(query, " last WRITE, history WRITE ");
    74   |
    75   |     sql_err=SQ_execute_query(tr->sql_connection, query->str, NULL);
    76   |
    77   |     /*fprintf(stderr,"%s\n", query->str);*/
    78   |
    79   |
    80   | /* Process AUX and LEAF tables */
    81   |     for (i=TAB_START; tables[tr->class_type][i] != NULL; i++) {
    82   |     /* Delete what has been inserted */
    83   |     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);
    84   |     sql_err=SQ_execute_query(tr->sql_connection, query->str, NULL);
    85   |
    86   |     /* Normalize what has been updated/touched */
    87   |     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);
    88   |     sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
    89   |   }
    90   |
    91   | /* Process MAIN tables */
    92   |     g_string_sprintf(query, "DELETE FROM %s WHERE  object_id=%ld AND thread_id=%d",
    93   |                              DF_get_class_sql_table(tr->class_type), tr->object_id, tr->thread_ins);
    94   |     sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
    95   |
    96   |     /* This is needed only for objects with dummies, as they are updated with TR_UPDATE */
    97   |     /* We use this tag when commiting the update to set dummy==0 */
    98   |     /* XXX may be later this should be reconsidered */
    99   |     g_string_sprintf(query, "UPDATE %s SET thread_id=0 WHERE  object_id=%ld AND thread_id=%d",
    100  |                              DF_get_class_sql_table(tr->class_type), tr->object_id, tr->thread_upd);
    101  |     sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
    102  |
    103  | /* Now tables  that might be affected by dummies */
    104  |     for(j=0; j < tr->ndummy; j++)
    105  |     for (i=0; tables[tr->class_type][i] != NULL; i++) {
    106  |     	g_string_sprintf(query, "DELETE FROM %s WHERE object_id=%ld ", tables[tr->class_type][i], tr->dummy_id[j]);
    107  |     	sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
    108  |     }
    109  |
    110  | /* Rollback last and history tables */
    111  |     if(ACT_UPDATE(tr->action)) { /* so we are updating an object */
    112  |    g_string_sprintf(query, "DELETE FROM history WHERE object_id=%ld AND sequence_id=%ld", tr->object_id, tr->sequence_id-1);
    113  |    sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
    114  |    /* we do not need to delete a row in the last for updates    */
    115  |   }
    116  |     else { /* we failed to create an object */
    117  |       sequence_id=1; /* sequence start == 1 */
    118  |    g_string_sprintf(query, "DELETE FROM last WHERE object_id=%ld AND sequence_id=%ld", tr->object_id, sequence_id);
    119  |    sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
    120  |   }
    121  |
    122  |
    123  |     for(j=0; j < tr->ndummy; j++){/* if dummies have been created */
    124  | 	 g_string_sprintf(query, "DELETE FROM last WHERE object_id=%ld ", tr->dummy_id[j]);
    125  | 	 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
    126  |   }
    127  |
    128  |   /* Unlock all tables */
    129  |   g_string_sprintf(query, "UNLOCK TABLES ");
    130  |   sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
    131  |
    132  |
    133  |   g_string_free(query, TRUE);
    134  |   return(0);
    135  | } /* rollback() */
    136  |
    137  |
    138  | /************************************************************
    139  | * int commit()                                              *
    140  | *                                                           *
    141  | * Commits the transaction                                   *
    142  | *                                                           *
    143  | * It locks all relevant tables and processes the rollback   *
    144  | * General approach is to clean up all new and updated       *
    145  | * records related to the transaction                        *
    146  | * (thread_id==thread_ins) and (thread_id==thread_upd),      *
    147  | * and delete untouched ones (thread_id==0)                  *
    148  | *                                                           *
    149  | ************************************************************/
    150  |
    151  | int commit(Transaction_t *tr) {
    152  | GString *query;
    153  | int err=0;
    154  | int i,j;
    155  | A_Type_t attr_type;
    156  | int sql_err;
    157  |
    158  | if(ACT_DELETE(tr->action)) return(0);
    159  |
    160  |  if ((query = g_string_sized_new(STR_XXL)) == NULL){
    161  |    fprintf(stderr, "E: cannot allocate gstring\n");
    162  |    tr->succeeded=0;
    163  |    tr->error|=ERROR_U_MEM;
    164  |    return(ERROR_U_MEM);
    165  |  }
    166  |
    167  | /* Lock all relevant tables */
    168  |     g_string_sprintf(query, "LOCK TABLES %s WRITE,", DF_get_class_sql_table(tr->class_type));
    169  |
    170  |     for (i=0; tables[tr->class_type][i] != NULL; i++)
    171  |       g_string_sprintfa(query, " %s WRITE,", tables[tr->class_type][i]);
    172  |
    173  |     for (i=TAB_START; tables[tr->class_type][i] != NULL; i++)
    174  |       g_string_sprintfa(query, " %s WRITE,", tables[tr->class_type][i]);
    175  |
    176  |     g_string_sprintfa(query, " last WRITE, history WRITE ");
    177  |
    178  |     sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
    179  |
    180  | /* fprintf(stderr,"%s\n", query->str); */
    181  |
    182  | /* Commit the transaction for AUX and LEAF tables that may be affected (taken from object template) */
    183  |   for (i=TAB_START; tables[tr->class_type][i] != NULL; i++) {
    184  |  /* Delete old records from the tables */
    185  |     g_string_sprintf(query, "DELETE FROM %s WHERE object_id=%ld AND thread_id=0 ", tables[tr->class_type][i], tr->object_id);
    186  |     sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
    187  |     /*    fprintf(stderr, "D: query (del old): %s\n", query->str);  */
    188  |
    189  |  /* Set thread_id to 0 to commit the transaction */
    190  |     g_string_sprintf(query, "UPDATE %s SET thread_id=0 WHERE object_id=%ld", tables[tr->class_type][i], tr->object_id);
    191  |     sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
    192  |     /*    fprintf(stderr, "D: query (com new): %s\n", query->str); */
    193  |   }
    194  |
    195  | /* Commit the transaction for the MAIN tables */
    196  |
    197  | /* Commit the transaction for person_role, mntner, as_set, route_set tables */
    198  | /* They require different handling because of dummies */
    199  | /* The rule is: Update: dummy->0, Insert: preserve dummy value */
    200  | /* These tables do not require deletions since we cannot have such condition (object_id==0 AND thread_id==0) */
    201  |  if((tr->class_type==C_PN) || (tr->class_type==C_RO) ||
    202  |    (tr->class_type==C_AS) || (tr->class_type==C_RS) ||
    203  |    (tr->class_type==C_MT)){
    204  |
    205  |  /* Process the rows updated/touched */
    206  |     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);
    207  |     sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
    208  |  }
    209  |
    210  |  switch (tr->class_type) {
    211  |    case C_IR:
    212  |    case C_IN:
    213  |    case C_I6:
    214  |    case C_FS:
    215  |     if((tr->save)){ /* Some special processing for tables with the second attribute */
    216  |      /* Update the second field of the table with query like one below */
    217  |      /* UPDATE %s SET thread_id=%d, local_as='%s' WHERE object_id=%ld */
    218  |
    219  |      switch(tr->class_type) {
    220  |       /* Local-as for inet-rtr */
    221  |       case C_IR: attr_type=A_LA;
    222  |                  break;
    223  |       /* netname for inetnum and inet6num */
    224  |       case C_IN:
    225  |       case C_I6: attr_type=A_NA;
    226  |                  break;
    227  |       /* filter for filter-set */
    228  |       case C_FS: attr_type=A_FI;
    229  |                  break;
    230  |       default:
    231  |                  die;
    232  |                  break;
    233  |      }
    234  |      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);
    235  |      sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
    236  |     }
    237  |     else die;
    238  |     break;
    239  |
    240  |    default:
    241  |  /* Process all other MAIN tables for updates/inserts and person_role, mntner, as_set, route_set tables for rows inserts */
    242  |     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);
    243  |     sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
    244  |     break;
    245  |  }
    246  |
    247  |
    248  | /* for tables that might be affected by dummies */
    249  |  for(j=0; j < tr->ndummy; j++)/* if dummies have been created */
    250  |    for (i=0; tables[tr->class_type][i] != NULL; i++) {
    251  |     g_string_sprintf(query, "UPDATE %s SET thread_id=0 WHERE object_id=%ld ", tables[tr->class_type][i], tr->dummy_id[j]);
    252  |     sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
    253  |  }
    254  |
    255  |
    256  |    for(j=0; j < tr->ndummy; j++){/* if dummies have been created*/
    257  | 	 g_string_sprintf(query, "UPDATE last SET thread_id=0 WHERE object_id=%ld ", tr->dummy_id[j]);
    258  | 	 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
    259  |   }
    260  |
    261  |  /* Unlock all tables */
    262  |  g_string_sprintf(query, "UNLOCK TABLES ");
    263  |  sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
    264  |
    265  |  /* Update radix tree for route, inetnum and inaddr-arpa domain*/
    266  |  if(tr->standalone==0) { /* only if server*/
    267  |
    268  |  /* Create a radix node for the object */
    269  |    if( (   (tr->class_type==C_RT)
    270  | 	|| (tr->class_type==C_IN)
    271  | 	|| (tr->class_type==C_I6)
    272  | 	|| (tr->class_type==C_DN))
    273  |        && (ACT_UPD_RX(tr->action))) {
    274  |      rp_upd_pack_t *packptr = tr->packptr;
    275  |
    276  |      packptr->key = tr->object_id;
    277  |
    278  |      if( RP_pack_node(RX_OPER_CRE, packptr, tr->source_hdl) == RX_OK ) {
    279  |        err = 0;
    280  |      } else {
    281  |        err = (-1) ;
    282  |      }
    283  |    }
    284  |    /* XXX Check for errors */
    285  |  }
    286  |
    287  |   g_string_free(query, TRUE);
    288  |   return(err);
    289  | } /* commit() */
    290  |
    291  |
    292  | /************************************************************
    293  | * int delete()                                              *
    294  | *                                                           *
    295  | * Deletes the object                                        *
    296  | *                                                           *
    297  | * It checks for referential integrity and then deletes the  *
    298  | * object from all relevant tables. Then it updates the      *
    299  | * radix tree for routes, inetnums and rev.domains           *
    300  | *                                                           *
    301  | ************************************************************/
    302  | int delete(Transaction_t *tr)
    303  | {
    304  | GString *query;
    305  | int err=0;
    306  | int i;
    307  | int num;
    308  | long ref_id;
    309  | long num_rec;
    310  | long timestamp;
    311  |
    312  | char sobject_id[STR_M];
    313  | char *sql_str;
    314  | int sql_err;
    315  |
    316  |
    317  |  /* Try to allocate g_string. Return on error */
    318  |  if ((query = g_string_sized_new(STR_XXL)) == NULL){
    319  |    fprintf(stderr, "E: cannot allocate gstring\n");
    320  |    tr->succeeded=0;
    321  |    tr->error|=ERROR_U_MEM;
    322  |    return(ERROR_U_MEM);
    323  |  }
    324  |
    325  |
    326  | /* Check for referential integrity of deletion */
    327  |
    328  |    sprintf(sobject_id, "%ld", tr->object_id);
    329  |
    330  |    switch(tr->class_type){
    331  |     case C_PN:
    332  |     case C_RO:
    333  |
    334  |        /* Check that this person/role object is not referenced */
    335  |
    336  |        for (i=0; t_ipn[i] != NULL; i++) {
    337  |         /* Calculate number of references */
    338  |         sql_str= get_field_str(tr->sql_connection, "COUNT(*)", t_ipn[i], "pe_ro_id", sobject_id, NULL);
    339  |         if(sql_str) {
    340  |          num_rec = atol(sql_str);  free(sql_str);
    341  |          ref_id=tr->object_id;
    342  |          /* Check if it is a self reference (for role objects) */
    343  |          if(num_rec==1) {
    344  |           sql_str= get_field_str(tr->sql_connection, "object_id", t_ipn[i], "pe_ro_id", sobject_id, NULL);
    345  |           if(sql_str) {
    346  |            ref_id = atol(sql_str);  free(sql_str);
    347  |           } else {
    348  |            tr->succeeded=0; tr->error |= ERROR_U_DBS; break;
    349  |           }
    350  |          }
    351  |          /* If there are references (and not the only self reference) we cannot delete */
    352  |          if((num_rec>1) || (ref_id!=tr->object_id)) {
    353  |            g_string_sprintfa(tr->error_script,"E[%d][%ld]:ref integrity: %s\n" ,ERROR_U_OBJ, num_rec, t_ipn[i]);
    354  |            tr->succeeded=0; tr->error |= ERROR_U_OBJ;
    355  |          }
    356  |         } else {
    357  |         /* SQL error occured */
    358  |          tr->succeeded=0; tr->error |= ERROR_U_DBS;
    359  |          g_string_sprintfa(tr->error_script,"E[%d][%s]:%s\n", ERROR_U_DBS, t_ipn[i], SQ_error(tr->sql_connection));
    360  |         }
    361  |        }
    362  |
    363  |        /* Check that this person/role object is not referenced by name (legacy stuff) */
    364  |        /* But allow overriding this check in NRTM mode and with override_integrity    */
    365  |        if(tr->dummy==1)break;
    366  |
    367  |        for (i=0; t_ipn[i] != NULL; i++) {
    368  |         /* Calculate number of references */
    369  |
    370  |         g_string_sprintf(query, "SELECT COUNT(*) FROM %s, person_role "
    371  |                                 "WHERE person_role.object_id=%s.pe_ro_id "
    372  |                                 "AND person_role.nic_hdl='%s' ", t_ipn[i], t_ipn[i], tr->save);
    373  |
    374  |         sql_str= get_qresult_str(tr->sql_connection, query->str);
    375  |         if(sql_str) {
    376  |          num_rec = atol(sql_str);  free(sql_str);
    377  |          /* If there are references (no self reference is possible in this case) we cannot delete */
    378  |          if(num_rec>0) {
    379  |            g_string_sprintfa(tr->error_script,"E[%d][%ld]:ref integrity: %s\n" ,ERROR_U_OBJ, num_rec, t_ipn[i]);
    380  |            tr->succeeded=0; tr->error |= ERROR_U_OBJ;
    381  |          }
    382  |         } else {
    383  |         /* SQL error occured */
    384  |          tr->succeeded=0; tr->error |= ERROR_U_DBS;
    385  |          g_string_sprintfa(tr->error_script,"E[%d][%s]:%s\n", ERROR_U_DBS, t_ipn[i], SQ_error(tr->sql_connection));
    386  |         }
    387  |        }
    388  |
    389  |        break;
    390  |
    391  |     case C_MT:
    392  |
    393  |         /* Check that this mntner object is not referenced */
    394  |
    395  |        for (i=0; t_imt[i] != NULL; i++) {
    396  |        /* Calculate number of references */
    397  |         sql_str= get_field_str(tr->sql_connection, "COUNT(*)", t_imt[i], "mnt_id", sobject_id, NULL);
    398  |         if(sql_str) {
    399  |          num_rec = atol(sql_str);  free(sql_str);
    400  |          ref_id=tr->object_id;
    401  |          /* Check if it is a self reference  */
    402  |          if(num_rec==1) {
    403  |             sql_str= get_field_str(tr->sql_connection, "object_id", t_imt[i], "mnt_id", sobject_id, NULL);
    404  |             if(sql_str) {
    405  |               ref_id = atol(sql_str);  free(sql_str);
    406  |             } else {
    407  |               tr->succeeded=0; tr->error |= ERROR_U_DBS; break;
    408  |             }
    409  |          }
    410  |          /* If there are references (and not the only self reference) we cannot delete */
    411  |          if((num_rec>1) || (ref_id!=tr->object_id)) {
    412  |            g_string_sprintfa(tr->error_script,"E[%d][%ld]:ref integrity: %s\n" ,ERROR_U_OBJ, num_rec, t_imt[i]);
    413  |            tr->succeeded=0; tr->error |= ERROR_U_OBJ;
    414  |          }
    415  |         } else {
    416  |          tr->succeeded=0; tr->error |= ERROR_U_DBS;
    417  |         }
    418  |        }
    419  |        break;
    420  |
    421  |     case C_RS:
    422  |     case C_AS:
    423  |         /* Check that this set object is not referenced */
    424  |         /* Calculate number of references */
    425  |         sql_str= get_field_str(tr->sql_connection, "COUNT(*)", "member_of", "set_id", sobject_id, NULL);
    426  |         if(sql_str) {
    427  |          num_rec = atol(sql_str);  free(sql_str);
    428  |          /* XXX though set may contain other sets as memebers, */
    429  |          /* there is no member-of attribute in these objects. */
    430  |          /* So no self-reference is possible */
    431  |          if(num_rec!=0) {
    432  |            g_string_sprintfa(tr->error_script,"E[%d][%ld]:ref integrity: %s\n" ,ERROR_U_OBJ, num_rec, "member_of");
    433  |            /*tr->succeeded=0; tr->error |= ERROR_U_OBJ;*/
    434  | 	  /* XXX Do not refuse the transaction but change the object to dummy */
    435  | 	  /* Update the history table */
    436  |                g_string_sprintf(query,  "INSERT history "
    437  | 	                                "SELECT 0, object_id, sequence_id, timestamp, object_type, object "
    438  |                                         "FROM last "
    439  |                                         "WHERE object_id=%ld ", tr->object_id);
    440  |
    441  |
    442  |                sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
    443  |                if (sql_err) {
    444  |                 fprintf(stderr, "E ERROR!<perform_update>: INSERT history failed:[%d][%s]\n", num, query->str);
    445  |                 tr->succeeded=0;
    446  |                 tr->error |=ERROR_U_DBS;
    447  |                }
    448  |
    449  |                /* get sequence number */
    450  |                tr->sequence_id = get_sequence_id(tr);
    451  |                tr->sequence_id++;
    452  |
    453  |                /* insert new version into the last */
    454  |                timestamp=time(NULL);
    455  |
    456  | 	      /* update the main table */
    457  | 	      g_string_sprintf(query, "UPDATE %s SET dummy=1 WHERE object_id=%ld ", DF_get_class_sql_table(tr->class_type), tr->object_id);
    458  |
    459  |               sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
    460  |               if (sql_err) {
    461  |                fprintf(stderr, "E ERROR!<perform_update>: UPDATE last failed: [%d][%s]\n", num, query->str);
    462  |                tr->succeeded=0;
    463  |                tr->error |= ERROR_U_DBS;
    464  |               }
    465  |
    466  |               /* empty the contents, but leave in the table to restrict re-use of object_id */
    467  |               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, timestamp, tr->object_id);
    468  |
    469  |               sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
    470  |               if (sql_err) {
    471  |                fprintf(stderr, "E ERROR!<perform_update>: UPDATE last failed: [%d][%s]\n", num, query->str);
    472  |                tr->succeeded=0;
    473  |                tr->error |= ERROR_U_DBS;
    474  |               }
    475  |               return(0);
    476  |
    477  |          }
    478  |         } else {
    479  |          tr->succeeded=0; tr->error |= ERROR_U_DBS;
    480  |         }
    481  |         break;
    482  |
    483  |     default:
    484  |         break;
    485  |    }
    486  |
    487  |  /* Check if we have passed referential integrity check */
    488  |  if(tr->succeeded==0){
    489  |        return(-1);
    490  |  }
    491  |
    492  |
    493  | /* Lock all relevant tables */
    494  |     g_string_sprintf(query, "LOCK TABLES %s WRITE,", DF_get_class_sql_table(tr->class_type));
    495  |
    496  |     for (i=0; tables[tr->class_type][i] != NULL; i++)
    497  |       g_string_sprintfa(query, " %s WRITE,", tables[tr->class_type][i]);
    498  |
    499  |     for (i=TAB_START; tables[tr->class_type][i] != NULL; i++)
    500  |       g_string_sprintfa(query, " %s WRITE,", tables[tr->class_type][i]);
    501  |
    502  |     g_string_sprintfa(query, " last WRITE, history WRITE ");
    503  |
    504  |     sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
    505  |
    506  |     for (i=TAB_START; tables[tr->class_type][i] != NULL; i++) {
    507  |     g_string_sprintf(query, "DELETE FROM %s WHERE object_id=%ld ", tables[tr->class_type][i], tr->object_id);
    508  |     sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
    509  |     /*    fprintf(stderr, "D: query (delete): %s\n", query->str);*/
    510  |   }
    511  |
    512  | /* Process the MAIN table  */
    513  |     g_string_sprintf(query, "DELETE FROM %s WHERE object_id=%ld ", DF_get_class_sql_table(tr->class_type), tr->object_id);
    514  |     sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
    515  |
    516  | /* Update the history table */
    517  |     g_string_sprintf(query,     "INSERT history "
    518  | 				"SELECT 0, object_id, sequence_id, timestamp, object_type, object "
    519  |        				"FROM last "
    520  |        				"WHERE object_id=%ld ", tr->object_id);
    521  |
    522  |
    523  |   sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
    524  |   if (sql_err) {
    525  |          fprintf(stderr, "E ERROR!<perform_update>: INSERT history failed:[%d][%s]\n", num, query->str);
    526  |          tr->succeeded=0;
    527  |          tr->error |=ERROR_U_DBS;
    528  |   }
    529  |
    530  |   /* get sequence number */
    531  |   tr->sequence_id = get_sequence_id(tr);
    532  |   tr->sequence_id++;
    533  |
    534  |   /* insert new version into the last */
    535  |   timestamp=time(NULL);
    536  |
    537  |  /* empty the contents, but leave in the table to restrict re-use of object_id */
    538  |   g_string_sprintf(query, "UPDATE last SET object='', timestamp=%ld  WHERE object_id=%ld ", timestamp, tr->object_id);
    539  |
    540  |   sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
    541  |   if (sql_err) {
    542  |   	fprintf(stderr, "E ERROR!<perform_update>: UPDATE last failed: [%d][%s]\n", num, query->str);
    543  |          tr->succeeded=0;
    544  |          tr->error |= ERROR_U_DBS;
    545  |   }
    546  |
    547  |
    548  |   /* Do more in the forest
    549  |    * Update radix tree for route and inetnum
    550  |    */
    551  |   if(tr->standalone==0) { /* only if server */
    552  |   /* Collect some data for radix tree and NH repository update */
    553  |     g_slist_foreach((tr->object)->attributes, get_rx_data, tr);
    554  |
    555  |     /* Only for these types of objects and only if we have collected data (tr->save != NULL) */
    556  |     if( (   (tr->class_type==C_RT)
    557  | 	 || (tr->class_type==C_IN)
    558  | 	 || (tr->class_type==C_I6)
    559  | 	 || (tr->class_type==C_DN))
    560  | 	&& (ACT_UPD_RX(tr->action))) {
    561  |       rp_upd_pack_t *packptr = tr->packptr;
    562  |
    563  |       packptr->key = tr->object_id;
    564  |       if( RP_pack_node(RX_OPER_DEL, packptr, tr->source_hdl) == RX_OK ) {
    565  | 	err = 0;
    566  |       } else {
    567  | 	err = (-1) ;
    568  |       }
    569  |     }
    570  |   }
    571  |
    572  |  /* Unlock all tables */
    573  |   g_string_sprintf(query, "UNLOCK TABLES ");
    574  |   sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
    575  |
    576  |   g_string_free(query, TRUE);
    577  |
    578  |   return(err);
    579  |
    580  | } /* delete() */