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