modules/ud/ud_comrol.c
/* [<][>][^][v][top][bottom][index][help] */
FUNCTIONS
This source file includes following functions.
- rollback
- commit
- delete
1 /***************************************
2 $Revision: 1.20 $
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 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) {
/* [<][>][^][v][top][bottom][index][help] */
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)
/* [<][>][^][v][top][bottom][index][help] */
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
507 /* Update the history table */
508 g_string_sprintf(query, "INSERT history "
509 "SELECT 0, object_id, sequence_id, timestamp, object_type, object "
510 "FROM last "
511 "WHERE object_id=%ld ", tr->object_id);
512
513 /* Delete records from the leaf and aux tables */
514 for (i=TAB_START; tables[tr->class_type][i] != NULL; i++) {
515 g_string_sprintf(query, "DELETE FROM %s WHERE object_id=%ld ", tables[tr->class_type][i], tr->object_id);
516 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
517 /* fprintf(stderr, "D: query (delete): %s\n", query->str);*/
518 }
519
520
521 /* Process the MAIN table */
522 g_string_sprintf(query, "DELETE FROM %s WHERE object_id=%ld ", DF_get_class_sql_table(tr->class_type), tr->object_id);
523 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
524
525
526 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
527 if (sql_err) {
528 fprintf(stderr, "E ERROR!<perform_update>: INSERT history failed:[%d][%s]\n", num, query->str);
529 tr->succeeded=0;
530 tr->error |=ERROR_U_DBS;
531 }
532
533 /* get sequence number */
534 tr->sequence_id = get_sequence_id(tr);
535 tr->sequence_id++;
536
537 /* insert new version into the last */
538 timestamp=time(NULL);
539
540 /* empty the contents, but leave in the table to restrict re-use of object_id */
541 g_string_sprintf(query, "UPDATE last SET object='', timestamp=%ld WHERE object_id=%ld ", timestamp, tr->object_id);
542
543 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
544 if (sql_err) {
545 fprintf(stderr, "E ERROR!<perform_update>: UPDATE last failed: [%d][%s]\n", num, query->str);
546 tr->succeeded=0;
547 tr->error |= ERROR_U_DBS;
548 }
549
550
551 /* Do more in the forest
552 * Update radix tree for route and inetnum
553 */
554 if(tr->standalone==0) { /* only if server */
555 /* Collect some data for radix tree and NH repository update */
556 g_slist_foreach((tr->object)->attributes, get_rx_data, tr);
557
558 /* Only for these types of objects and only if we have collected data (tr->save != NULL) */
559 if( ( (tr->class_type==C_RT)
560 || (tr->class_type==C_IN)
561 || (tr->class_type==C_I6)
562 || (tr->class_type==C_DN))
563 && (ACT_UPD_RX(tr->action))) {
564 rp_upd_pack_t *packptr = tr->packptr;
565
566 packptr->key = tr->object_id;
567 if( RP_pack_node(RX_OPER_DEL, packptr, tr->source_hdl) == RX_OK ) {
568 err = 0;
569 } else {
570 err = (-1) ;
571 }
572 }
573 }
574
575 /* Unlock all tables */
576 g_string_sprintf(query, "UNLOCK TABLES ");
577 sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
578
579 g_string_free(query, TRUE);
580
581 return(err);
582
583 } /* delete() */