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() */