modules/ud/ud_comrol.c
/* [<][>][^][v][top][bottom][index][help] */
FUNCTIONS
This source file includes following functions.
- rollback
- commit
- delete
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) {
/* [<][>][^][v][top][bottom][index][help] */
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) {
/* [<][>][^][v][top][bottom][index][help] */
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)
/* [<][>][^][v][top][bottom][index][help] */
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() */