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