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