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