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