1 | /***************************************
2 | $Revision: 1.5 $
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 |
37 | #define RIPE_REG 17
38 |
39 | /************************************************************
40 | * int rollback(Transaction_t *tr)
41 | * Rollback the transaction
42 | *
43 | * **********************************************************/
44 | int rollback(Transaction_t *tr) {
45 | SQ_result_set_t * sql_result;
46 | GString *query;
47 | long sequence_id;
48 | int i, j;
49 |
50 | if(tr->action==TR_DELETE) return(0);
51 |
52 | if ((query = g_string_sized_new(STR_XXL)) == NULL){
53 | fprintf(stderr, "E: cannot allocate gstring\n");
54 | tr->succeeded=0;
55 | tr->error |= ERROR_U_MEM;
56 | return(ERROR_U_MEM); }
57 |
58 | /* Lock all relevant tables */
59 | if(tr->class_type==C_IR) g_string_sprintf(query, "LOCK TABLES inet_rtr WRITE");
60 | else g_string_sprintf(query, "LOCK TABLES %s WRITE,", tables[tr->class_type][0]);
61 |
62 | for (i=1; tables[tr->class_type][i] != NULL; i++)
63 | g_string_sprintfa(query, " %s WRITE,", tables[tr->class_type][i]);
64 |
65 | for (i=TAB_START; tables[tr->class_type][i] != NULL; i++)
66 | g_string_sprintfa(query, " %s WRITE,", tables[tr->class_type][i]);
67 |
68 | g_string_sprintfa(query, " last WRITE, history WRITE ");
69 |
70 | sql_result=SQ_execute_query(SQ_NOSTORE, tr->sql_connection, query->str);
71 |
72 | //fprintf(stderr,"%s\n", query->str);
73 |
74 |
75 | /* Process AUX and LEAF tables */
76 | for (i=TAB_START; tables[tr->class_type][i] != NULL; i++) {
77 | /* Delete what has been inserted */
78 | 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);
79 | sql_result=SQ_execute_query(SQ_NOSTORE, tr->sql_connection, query->str);
80 | // fprintf(stderr, "D: query (rollback): %s\n", query->str);
81 |
82 | /* Normalize what has been updated/touched */
83 | 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);
84 | sql_result=SQ_execute_query(SQ_NOSTORE, tr->sql_connection, query->str);
85 | // fprintf(stderr, "D: query (rollback): %s\n", query->str);
86 | }
87 |
88 | if(tr->class_type==C_IR){
89 | /* Don't forget about inet_rtr, since we haven't included it in the Tables. */
90 | g_string_sprintf(query, "DELETE FROM inet_rtr WHERE object_id=%ld AND thread_id=%d", tr->object_id, tr->thread_ins);
91 | sql_result=SQ_execute_query(SQ_NOSTORE, tr->sql_connection, query->str);
92 | // fprintf(stderr, "D: query (rollback): %s\n", query->str);
93 |
94 | g_string_sprintf(query, "UPDATE inet_rtr SET thread_id=0 WHERE object_id=%ld AND thread_id=%d", tr->object_id, tr->thread_upd);
95 | sql_result=SQ_execute_query(SQ_NOSTORE, tr->sql_connection, query->str);
96 | // fprintf(stderr, "D: query (rollback): %s\n", query->str);
97 | }
98 | else {
99 | /* Process the MAIN tables (they appear first in the table list */
100 | g_string_sprintf(query, "DELETE FROM %s WHERE object_id=%ld AND thread_id=%d", tables[tr->class_type][0], tr->object_id, tr->thread_ins);
101 | sql_result=SQ_execute_query(SQ_NOSTORE, tr->sql_connection, query->str);
102 | // fprintf(stderr, "D: query (rollback): %s\n", query->str);
103 |
104 | g_string_sprintf(query, "UPDATE %s SET thread_id=0 WHERE object_id=%ld AND thread_id=%d", tables[tr->class_type][0], tr->object_id, tr->thread_upd);
105 | sql_result=SQ_execute_query(SQ_NOSTORE, tr->sql_connection, query->str);
106 | // fprintf(stderr, "D: query (rollback): %s\n", query->str);
107 | }
108 |
109 | /* Now tables that might be affected by dummies */
110 | for(j=0; j < tr->ndummy; j++)
111 | for (i=1; tables[tr->class_type][i] != NULL; i++) {
112 | g_string_sprintf(query, "DELETE FROM %s WHERE object_id=%ld ", tables[tr->class_type][i], tr->dummy_id[j]);
113 | sql_result=SQ_execute_query(SQ_NOSTORE, tr->sql_connection, query->str);
114 | // fprintf(stderr, "D: query (rollback DUMMY): %s\n", query->str);
115 | }
116 |
117 | /* Rollback last and history tables */
118 | if(tr->action==TR_UPDATE) { // so we are updating an object
119 | g_string_sprintf(query, "DELETE FROM history WHERE object_id=%ld AND sequence_id=%ld", tr->object_id, tr->sequence_id);
120 | sql_result=SQ_execute_query(SQ_NOSTORE, tr->sql_connection, query->str);
121 | // fprintf(stderr, "D: query (rollback): %s\n", query->str);
122 | // we do not need to delete a row in the last for updates
123 | }
124 | else { // we failed to create an object
125 | sequence_id=1; // sequence start == 1
126 | g_string_sprintf(query, "DELETE FROM last WHERE object_id=%ld AND sequence_id=%ld", tr->object_id, sequence_id);
127 | sql_result=SQ_execute_query(SQ_NOSTORE, tr->sql_connection, query->str);
128 | // fprintf(stderr, "D: query (rollback): %s\n", query->str);
129 | }
130 |
131 |
132 | for(j=0; j < tr->ndummy; j++){// if dummies have been created
133 | g_string_sprintf(query, "DELETE FROM last WHERE object_id=%ld ", tr->dummy_id[j]);
134 | sql_result=SQ_execute_query(SQ_NOSTORE, tr->sql_connection, query->str);
135 | // fprintf(stderr, "D: query (rollback DUMMY): %s\n", query->str);
136 | }
137 |
138 | /* Unlock all tables */
139 | g_string_sprintf(query, "UNLOCK TABLES ");
140 | sql_result=SQ_execute_query(SQ_NOSTORE, tr->sql_connection, query->str);
141 |
142 | //fprintf(stderr,"%s\n", query->str);
143 |
144 | g_string_free(query, TRUE);
145 | return(0);
146 | } /* rollback() */
147 |
148 | /************************************************************
149 | * int commit(Transaction_t *tr)
150 | * Commit the transaction
151 | *
152 | * **********************************************************/
153 | int commit(Transaction_t *tr) {
154 | rx_tree_t *mytree;
155 | SQ_result_set_t * sql_result;
156 | GString *query;
157 | int err=0;
158 | int i,j;
159 |
160 | if(tr->action==TR_DELETE) return(0);
161 |
162 | if ((query = g_string_sized_new(STR_XXL)) == NULL){
163 | fprintf(stderr, "E: cannot allocate gstring\n");
164 | tr->succeeded=0;
165 | tr->error|=ERROR_U_MEM;
166 | return(ERROR_U_MEM);
167 | }
168 |
169 | /* Lock all relevant tables */
170 | if(tr->class_type==C_IR) g_string_sprintf(query, "LOCK TABLES inet_rtr WRITE");
171 | else g_string_sprintf(query, "LOCK TABLES %s WRITE,", tables[tr->class_type][0]);
172 |
173 | for (i=1; tables[tr->class_type][i] != NULL; i++)
174 | g_string_sprintfa(query, " %s WRITE,", tables[tr->class_type][i]);
175 |
176 | for (i=TAB_START; tables[tr->class_type][i] != NULL; i++)
177 | g_string_sprintfa(query, " %s WRITE,", tables[tr->class_type][i]);
178 |
179 | g_string_sprintfa(query, " last WRITE, history WRITE ");
180 |
181 | sql_result=SQ_execute_query(SQ_NOSTORE, tr->sql_connection, query->str);
182 |
183 | //fprintf(stderr,"%s\n", query->str);
184 |
185 | /* Commit the transaction for AUX and LEAF tables that may be affected (taken from object template) */
186 | for (i=TAB_START; tables[tr->class_type][i] != NULL; i++) {
187 | /* Delete old records from the tables */
188 | g_string_sprintf(query, "DELETE FROM %s WHERE object_id=%ld AND thread_id=0 ", tables[tr->class_type][i], tr->object_id);
189 | sql_result=SQ_execute_query(SQ_NOSTORE, tr->sql_connection, query->str);
190 | // fprintf(stderr, "D: query (del old): %s\n", query->str);
191 |
192 | /* Set thread_id to 0 to commit the transaction */
193 | g_string_sprintf(query, "UPDATE %s SET thread_id=0 WHERE object_id=%ld", tables[tr->class_type][i], tr->object_id);
194 | sql_result=SQ_execute_query(SQ_NOSTORE, tr->sql_connection, query->str);
195 | // fprintf(stderr, "D: query (com new): %s\n", query->str);
196 | }
197 |
198 | /* Commit the transaction for the MAIN tables */
199 |
200 | /* Commit the transaction for person_role, mntner, as_set, route_set tables */
201 | /* They require different handling because of dummies */
202 | /* The rule is: Update: dummy->0, Insert: preserve dummy value */
203 | /* These tables do not require deletions since we cannot have such condition (object_id==0 AND thread_id==0) */
204 | if((tr->class_type==C_PN) || (tr->class_type==C_RO) ||
205 | (tr->class_type==C_AS) || (tr->class_type==C_RS) ||
206 | (tr->class_type==C_MT)){
207 |
208 | /* Process the rows updated/touched */
209 | g_string_sprintf(query, "UPDATE %s SET thread_id=0, dummy=0 WHERE object_id=%ld AND thread_id=%d ", tables[tr->class_type][0], tr->object_id, tr->thread_upd);
210 | sql_result=SQ_execute_query(SQ_NOSTORE, tr->sql_connection, query->str);
211 | // fprintf(stderr, "D: query (com new): %s\n", query->str);
212 | }
213 |
214 | if((tr->class_type==C_IR) && (tr->save)){ // Some special processing for inet_rtr - not good, but...
215 | /* Delete old records from the table */
216 | g_string_sprintf(query, "DELETE FROM inet_rtr WHERE thread_id=0 AND object_id=%ld", tr->object_id);
217 | sql_result=SQ_execute_query(SQ_NOSTORE, tr->sql_connection, query->str);
218 | // fprintf(stderr, "D: query (del old): %s\n", query->str);
219 |
220 | g_string_sprintf(query, "UPDATE inet_rtr SET thread_id=0, local_as='%s' WHERE object_id=%ld", (char *)tr->save, tr->object_id);
221 | sql_result=SQ_execute_query(SQ_NOSTORE, tr->sql_connection, query->str);
222 | // fprintf(stderr, "D: query (com new): %s\n", query->str);
223 | }
224 | else {
225 | /* Process all other MAIN tables for updates/inserts and person_role, mntner, as_set, route_set tables for rows inserts */
226 | g_string_sprintf(query, "UPDATE %s SET thread_id=0 WHERE object_id=%ld AND thread_id>0", tables[tr->class_type][0], tr->object_id);
227 | sql_result=SQ_execute_query(SQ_NOSTORE, tr->sql_connection, query->str);
228 | // fprintf(stderr, "D: query (com new): %s\n", query->str);
229 | }
230 |
231 |
232 | /* for tables that might be affected by dummies */
233 | for(j=0; j < tr->ndummy; j++)// if dummies have been created
234 | for (i=1; tables[tr->class_type][i] != NULL; i++) {
235 | g_string_sprintf(query, "UPDATE %s SET thread_id=0 WHERE object_id=%ld ", tables[tr->class_type][i], tr->dummy_id[j]);
236 | sql_result=SQ_execute_query(SQ_NOSTORE, tr->sql_connection, query->str);
237 | // fprintf(stderr, "D: query (com new DUMMY): %s\n", query->str);
238 | }
239 |
240 | // Update radix tree for route and inetnum
241 | if(tr->standalone==0) { // only if server
242 | if((tr->class_type==C_RT) && (tr->save)) {
243 | if (RX_get_tree( &mytree, RIPE_REG, IP_V4, RX_FAM_RT) != RX_OK )err=-1;
244 | else
245 | err=update_rx_bin(RX_OPER_CRE, mytree, (rx_bin_data_t *)tr->save, tr->object_id);
246 | }
247 |
248 | if((tr->class_type==C_IN) && (tr->save)) {
249 | if (RX_get_tree( &mytree, RIPE_REG, IP_V4, RX_FAM_IN) != RX_OK ) err=-1;
250 | else
251 | err=update_rx_inum(RX_OPER_CRE, mytree, (rx_inum_data_t *)tr->save, tr->object_id);
252 | }
253 | }
254 |
255 | /* Unlock all tables */
256 | g_string_sprintf(query, "UNLOCK TABLES ");
257 | sql_result=SQ_execute_query(SQ_NOSTORE, tr->sql_connection, query->str);
258 |
259 | //fprintf(stderr,"%s\n", query->str);
260 | g_string_free(query, TRUE);
261 | return(err);
262 | } /* commit() */
263 |
264 |
265 | /* Function to fill data for radix tree */
266 | static void get_rx_data(void *element_data, void *tr_ptr)
267 | {
268 | Attribute_t *attr = element_data;
269 | Transaction_t *tr = (Transaction_t *)tr_ptr;
270 | unsigned int prefix, prefix_length;
271 | unsigned int begin_in, end_in;
272 | static rx_bin_data_t rx_bin_data;
273 | static rx_inum_data_t rx_inum_data;
274 |
275 | switch(attr->type) {
276 | case A_RT:
277 | expand_rt(attr->value, &prefix, &prefix_length);
278 | save_rx_pref(&rx_bin_data, prefix, prefix_length);
279 | tr->save = (void *)&rx_bin_data;
280 | break;
281 | case A_IN:
282 | convert_in(attr->value, &begin_in, &end_in);
283 | save_rx_rang(&rx_inum_data, begin_in, end_in);
284 | tr->save = (void *)&rx_inum_data;
285 | break;
286 | default:
287 | break;
288 | }
289 | }
290 |
291 | /******************************************************
292 | *int delete(Transaction_t *tr)
293 | * Delete the object
294 | *
295 | *****************************************************/
296 | int delete(Transaction_t *tr)
297 | {
298 | SQ_result_set_t * sql_result;
299 | rx_tree_t *mytree;
300 | GString *query;
301 | int err=0;
302 | int i;
303 | int num;
304 | long sequence_id;
305 | long ref_id;
306 | long num_rec;
307 | long timestamp;
308 |
309 | char sobject_id[STR_M];
310 | char *sql_str;
311 |
312 |
313 | /* Check for referential integrity of deletion */
314 |
315 | sprintf(sobject_id, "%ld", tr->object_id);
316 |
317 | switch(tr->class_type){
318 | case C_PN:
319 | case C_RO:
320 |
321 | if(tr->dummy==1)break;
322 |
323 | for (i=0; t_ipn[i] != NULL; i++) {
324 | sql_str= get_field_str(tr, "COUNT(*)", t_ipn[i], "pe_ro_id", sobject_id, NULL);
325 | if(sql_str) {
326 | num_rec = atol(sql_str); free(sql_str);
327 | ref_id=tr->object_id;
328 | if(num_rec==1) {
329 | sql_str= get_field_str(tr, "object_id", t_ipn[i], "pe_ro_id", sobject_id, NULL);
330 | if(sql_str) {
331 | ref_id = atol(sql_str); free(sql_str);
332 | } else {
333 | tr->succeeded=0; tr->error |= ERROR_U_DBS; break;
334 | }
335 | }
336 | if((num_rec>1) || (ref_id!=tr->object_id)) {
337 | g_string_sprintfa(tr->error_script,"E[%d][%ld]:ref integrity: %s\n" ,ERROR_U_OBJ, num_rec, t_ipn[i]);
338 | tr->succeeded=0; tr->error |= ERROR_U_OBJ;
339 | }
340 | } else {
341 | tr->succeeded=0; tr->error |= ERROR_U_DBS;
342 | }
343 | }
344 | break;
345 |
346 | case C_MT:
347 |
348 | if(tr->dummy==1)break;
349 |
350 | for (i=0; t_imt[i] != NULL; i++) {
351 | sql_str= get_field_str(tr, "COUNT(*)", t_imt[i], "mnt_id", sobject_id, NULL);
352 | if(sql_str) {
353 | num_rec = atol(sql_str); free(sql_str);
354 | ref_id=tr->object_id;
355 | if(num_rec==1) {
356 | sql_str= get_field_str(tr, "object_id", t_imt[i], "mnt_id", sobject_id, NULL);
357 | if(sql_str) {
358 | ref_id = atol(sql_str); free(sql_str);
359 | } else {
360 | tr->succeeded=0; tr->error |= ERROR_U_DBS; break;
361 | }
362 | }
363 | if((num_rec>1) || (ref_id!=tr->object_id)) {
364 | g_string_sprintfa(tr->error_script,"E[%d][%ld]:ref integrity: %s\n" ,ERROR_U_OBJ, num_rec, t_imt[i]);
365 | tr->succeeded=0; tr->error |= ERROR_U_OBJ;
366 | }
367 | } else {
368 | tr->succeeded=0; tr->error |= ERROR_U_DBS;
369 | }
370 | }
371 | break;
372 |
373 | case C_RS:
374 | case C_AS:
375 | sql_str= get_field_str(tr, "COUNT(*)", "member_of", "set_id", sobject_id, NULL);
376 | if(sql_str) {
377 | num_rec = atol(sql_str); free(sql_str);
378 | ref_id=tr->object_id;
379 | if(num_rec==1) {
380 | sql_str= get_field_str(tr, "object_id", "member_of", "set_id", sobject_id, NULL);
381 | if(sql_str) {
382 | ref_id = atol(sql_str); free(sql_str);
383 | } else {
384 | tr->succeeded=0; tr->error |= ERROR_U_DBS; break;
385 | }
386 | }
387 | if((num_rec>1) || (ref_id!=tr->object_id)) {
388 | g_string_sprintfa(tr->error_script,"E[%d][%ld]:ref integrity: %s\n" ,ERROR_U_OBJ, num_rec, "member_of");
389 | tr->succeeded=0; tr->error |= ERROR_U_OBJ;
390 | }
391 | } else {
392 | tr->succeeded=0; tr->error |= ERROR_U_DBS;
393 | }
394 | break;
395 |
396 | default:
397 | break;
398 | }
399 |
400 | if(tr->succeeded==0){
401 | return(-1);
402 | }
403 |
404 |
405 | if ((query = g_string_sized_new(STR_XXL)) == NULL){
406 | fprintf(stderr, "E: cannot allocate gstring\n");
407 | tr->succeeded=0;
408 | tr->error|=ERROR_U_MEM;
409 | return(ERROR_U_MEM);
410 | }
411 |
412 |
413 | /* Lock all relevant tables */
414 | if(tr->class_type==C_IR) g_string_sprintf(query, "LOCK TABLES inet_rtr WRITE");
415 | else g_string_sprintf(query, "LOCK TABLES %s WRITE,", tables[tr->class_type][0]);
416 |
417 | for (i=1; tables[tr->class_type][i] != NULL; i++)
418 | g_string_sprintfa(query, " %s WRITE,", tables[tr->class_type][i]);
419 |
420 | for (i=TAB_START; tables[tr->class_type][i] != NULL; i++)
421 | g_string_sprintfa(query, " %s WRITE,", tables[tr->class_type][i]);
422 |
423 | g_string_sprintfa(query, " last WRITE, history WRITE ");
424 |
425 | sql_result=SQ_execute_query(SQ_NOSTORE, tr->sql_connection, query->str);
426 |
427 | //fprintf(stderr,"%s\n", query->str);
428 |
429 | for (i=TAB_START; tables[tr->class_type][i] != NULL; i++) {
430 | g_string_sprintf(query, "DELETE FROM %s WHERE object_id=%ld ", tables[tr->class_type][i], tr->object_id);
431 | sql_result=SQ_execute_query(SQ_NOSTORE, tr->sql_connection, query->str);
432 | // fprintf(stderr, "D: query (delete): %s\n", query->str);
433 | }
434 |
435 | /* process tables differently for these type of objects (because of dummy). Table should appear first */
436 | if((tr->class_type==C_PN) || (tr->class_type==C_RO) ||
437 | (tr->class_type==C_AS) || (tr->class_type==C_RS) ||
438 | (tr->class_type==C_MT)) {
439 | g_string_sprintf(query, "DELETE FROM %s WHERE object_id=%ld ", tables[tr->class_type][0], tr->object_id);
440 | sql_result=SQ_execute_query(SQ_NOSTORE, tr->sql_connection, query->str);
441 | // fprintf(stderr, "D: query (delete): %s\n", query->str);
442 | }
443 |
444 | if(tr->class_type==C_IR){
445 | /* Don't forget about inet_rtr, since we haven't included it in the Tables. */
446 | g_string_sprintf(query, "DELETE FROM inet_rtr WHERE object_id=%ld ", tr->object_id);
447 | sql_result=SQ_execute_query(SQ_NOSTORE, tr->sql_connection, query->str);
448 | // fprintf(stderr, "D: query (delete): %s\n", query->str);
449 | }
450 | else {
451 | /* Process the MAIN tables (they appear first in the table list */
452 | g_string_sprintf(query, "DELETE FROM %s WHERE object_id=%ld ", tables[tr->class_type][0], tr->object_id);
453 | sql_result=SQ_execute_query(SQ_NOSTORE, tr->sql_connection, query->str);
454 | // fprintf(stderr, "D: query (delete): %s\n", query->str);
455 | }
456 |
457 |
458 | g_string_sprintf(query, "INSERT history "
459 | "SELECT 0, object_id, sequence_id, timestamp, object_type, object "
460 | "FROM last "
461 | "WHERE object_id=%ld ", tr->object_id);
462 |
463 | //fprintf(stderr, "D: copying entry into the history table\n %s\n", query->str);
464 |
465 | sql_result=SQ_execute_query(SQ_STORE, tr->sql_connection, query->str);
466 | num = mysql_affected_rows(tr->sql_connection);
467 | if (sql_result)SQ_free_result(sql_result);
468 | if ((num == -1) || (num == 0)) {
469 | fprintf(stderr, "E ERROR!<perform_update>: INSERT history failed:[%d][%s]\n", num, query->str);
470 | tr->succeeded=0;
471 | tr->error |=ERROR_U_DBS;
472 | }
473 |
474 | // get sequence number
475 | sequence_id = get_sequence_id(tr);
476 |
477 | // insert new version into the last
478 | timestamp=time(NULL);
479 |
480 | g_string_sprintf(query, "UPDATE last SET object='' WHERE object_id=%ld ", tr->object_id);
481 |
482 | sql_result=SQ_execute_query(SQ_STORE, tr->sql_connection, query->str);
483 | num = mysql_affected_rows(tr->sql_connection);
484 | if (sql_result)SQ_free_result(sql_result);
485 | if ((num == -1) || (num == 0)) {
486 | fprintf(stderr, "E ERROR!<perform_update>: UPDATE last failed: [%d][%s]\n", num, query->str);
487 | tr->succeeded=0;
488 | tr->error |= ERROR_U_DBS;
489 | }
490 |
491 |
492 | // Do more in the forest
493 | // Update radix tree for route and inetnum
494 | if(tr->standalone==0) { // only if server
495 | g_slist_foreach((tr->object)->attributes, get_rx_data, tr);
496 | if((tr->class_type==C_RT) && (tr->save)) {
497 | if (RX_get_tree( &mytree, RIPE_REG, IP_V4, RX_FAM_RT) != RX_OK ) err=-1;
498 | else err=update_rx_bin(RX_OPER_DEL, mytree, (rx_bin_data_t *)tr->save, tr->object_id);
499 | }
500 |
501 | if((tr->class_type==C_IN) && (tr->save)) {
502 | if (RX_get_tree( &mytree, RIPE_REG, IP_V4, RX_FAM_IN) != RX_OK ) err=-1;
503 | else err=update_rx_inum(RX_OPER_DEL, mytree, (rx_inum_data_t *)tr->save, tr->object_id);
504 | }
505 | }
506 |
507 | /* Unlock all tables */
508 | g_string_sprintf(query, "UNLOCK TABLES ");
509 | sql_result=SQ_execute_query(SQ_NOSTORE, tr->sql_connection, query->str);
510 |
511 | //fprintf(stderr,"%s\n", query->str);
512 |
513 | g_string_free(query, TRUE);
514 |
515 | return(err);
516 |
517 | } /* delete() */