modules/ud/ud_comrol.c
/* [<][>][^][v][top][bottom][index][help] */
FUNCTIONS
This source file includes following functions.
- rollback
- commit
- get_rx_data
- delete
/***************************************
$Revision: 1.5 $
rollback(), commit(), delete() - rollback, commit update transaction, delete an object
Status: NOT REVUED, NOT TESTED
Author(s): Andrei Robachevsky
******************/ /******************
Modification History:
andrei (17/01/2000) Created.
******************/ /******************
Copyright (c) 2000 RIPE NCC
All Rights Reserved
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation, and that the name of the author not be
used in advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
***************************************/
#include "ud.h"
#include "ud_int.h"
#include "ud_comrol.h"
#define RIPE_REG 17
/************************************************************
* int rollback(Transaction_t *tr)
* Rollback the transaction
*
* **********************************************************/
int rollback(Transaction_t *tr) {
/* [<][>][^][v][top][bottom][index][help] */
SQ_result_set_t * sql_result;
GString *query;
long sequence_id;
int i, j;
if(tr->action==TR_DELETE) return(0);
if ((query = g_string_sized_new(STR_XXL)) == NULL){
fprintf(stderr, "E: cannot allocate gstring\n");
tr->succeeded=0;
tr->error |= ERROR_U_MEM;
return(ERROR_U_MEM); }
/* Lock all relevant tables */
if(tr->class_type==C_IR) g_string_sprintf(query, "LOCK TABLES inet_rtr WRITE");
else g_string_sprintf(query, "LOCK TABLES %s WRITE,", tables[tr->class_type][0]);
for (i=1; tables[tr->class_type][i] != NULL; i++)
g_string_sprintfa(query, " %s WRITE,", tables[tr->class_type][i]);
for (i=TAB_START; tables[tr->class_type][i] != NULL; i++)
g_string_sprintfa(query, " %s WRITE,", tables[tr->class_type][i]);
g_string_sprintfa(query, " last WRITE, history WRITE ");
sql_result=SQ_execute_query(SQ_NOSTORE, tr->sql_connection, query->str);
//fprintf(stderr,"%s\n", query->str);
/* Process AUX and LEAF tables */
for (i=TAB_START; tables[tr->class_type][i] != NULL; i++) {
/* Delete what has been inserted */
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);
sql_result=SQ_execute_query(SQ_NOSTORE, tr->sql_connection, query->str);
// fprintf(stderr, "D: query (rollback): %s\n", query->str);
/* Normalize what has been updated/touched */
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);
sql_result=SQ_execute_query(SQ_NOSTORE, tr->sql_connection, query->str);
// fprintf(stderr, "D: query (rollback): %s\n", query->str);
}
if(tr->class_type==C_IR){
/* Don't forget about inet_rtr, since we haven't included it in the Tables. */
g_string_sprintf(query, "DELETE FROM inet_rtr WHERE object_id=%ld AND thread_id=%d", tr->object_id, tr->thread_ins);
sql_result=SQ_execute_query(SQ_NOSTORE, tr->sql_connection, query->str);
// fprintf(stderr, "D: query (rollback): %s\n", query->str);
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);
sql_result=SQ_execute_query(SQ_NOSTORE, tr->sql_connection, query->str);
// fprintf(stderr, "D: query (rollback): %s\n", query->str);
}
else {
/* Process the MAIN tables (they appear first in the table list */
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);
sql_result=SQ_execute_query(SQ_NOSTORE, tr->sql_connection, query->str);
// fprintf(stderr, "D: query (rollback): %s\n", query->str);
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);
sql_result=SQ_execute_query(SQ_NOSTORE, tr->sql_connection, query->str);
// fprintf(stderr, "D: query (rollback): %s\n", query->str);
}
/* Now tables that might be affected by dummies */
for(j=0; j < tr->ndummy; j++)
for (i=1; tables[tr->class_type][i] != NULL; i++) {
g_string_sprintf(query, "DELETE FROM %s WHERE object_id=%ld ", tables[tr->class_type][i], tr->dummy_id[j]);
sql_result=SQ_execute_query(SQ_NOSTORE, tr->sql_connection, query->str);
// fprintf(stderr, "D: query (rollback DUMMY): %s\n", query->str);
}
/* Rollback last and history tables */
if(tr->action==TR_UPDATE) { // so we are updating an object
g_string_sprintf(query, "DELETE FROM history WHERE object_id=%ld AND sequence_id=%ld", tr->object_id, tr->sequence_id);
sql_result=SQ_execute_query(SQ_NOSTORE, tr->sql_connection, query->str);
// fprintf(stderr, "D: query (rollback): %s\n", query->str);
// we do not need to delete a row in the last for updates
}
else { // we failed to create an object
sequence_id=1; // sequence start == 1
g_string_sprintf(query, "DELETE FROM last WHERE object_id=%ld AND sequence_id=%ld", tr->object_id, sequence_id);
sql_result=SQ_execute_query(SQ_NOSTORE, tr->sql_connection, query->str);
// fprintf(stderr, "D: query (rollback): %s\n", query->str);
}
for(j=0; j < tr->ndummy; j++){// if dummies have been created
g_string_sprintf(query, "DELETE FROM last WHERE object_id=%ld ", tr->dummy_id[j]);
sql_result=SQ_execute_query(SQ_NOSTORE, tr->sql_connection, query->str);
// fprintf(stderr, "D: query (rollback DUMMY): %s\n", query->str);
}
/* Unlock all tables */
g_string_sprintf(query, "UNLOCK TABLES ");
sql_result=SQ_execute_query(SQ_NOSTORE, tr->sql_connection, query->str);
//fprintf(stderr,"%s\n", query->str);
g_string_free(query, TRUE);
return(0);
} /* rollback() */
/************************************************************
* int commit(Transaction_t *tr)
* Commit the transaction
*
* **********************************************************/
int commit(Transaction_t *tr) {
/* [<][>][^][v][top][bottom][index][help] */
rx_tree_t *mytree;
SQ_result_set_t * sql_result;
GString *query;
int err=0;
int i,j;
if(tr->action==TR_DELETE) return(0);
if ((query = g_string_sized_new(STR_XXL)) == NULL){
fprintf(stderr, "E: cannot allocate gstring\n");
tr->succeeded=0;
tr->error|=ERROR_U_MEM;
return(ERROR_U_MEM);
}
/* Lock all relevant tables */
if(tr->class_type==C_IR) g_string_sprintf(query, "LOCK TABLES inet_rtr WRITE");
else g_string_sprintf(query, "LOCK TABLES %s WRITE,", tables[tr->class_type][0]);
for (i=1; tables[tr->class_type][i] != NULL; i++)
g_string_sprintfa(query, " %s WRITE,", tables[tr->class_type][i]);
for (i=TAB_START; tables[tr->class_type][i] != NULL; i++)
g_string_sprintfa(query, " %s WRITE,", tables[tr->class_type][i]);
g_string_sprintfa(query, " last WRITE, history WRITE ");
sql_result=SQ_execute_query(SQ_NOSTORE, tr->sql_connection, query->str);
//fprintf(stderr,"%s\n", query->str);
/* Commit the transaction for AUX and LEAF tables that may be affected (taken from object template) */
for (i=TAB_START; tables[tr->class_type][i] != NULL; i++) {
/* Delete old records from the tables */
g_string_sprintf(query, "DELETE FROM %s WHERE object_id=%ld AND thread_id=0 ", tables[tr->class_type][i], tr->object_id);
sql_result=SQ_execute_query(SQ_NOSTORE, tr->sql_connection, query->str);
// fprintf(stderr, "D: query (del old): %s\n", query->str);
/* Set thread_id to 0 to commit the transaction */
g_string_sprintf(query, "UPDATE %s SET thread_id=0 WHERE object_id=%ld", tables[tr->class_type][i], tr->object_id);
sql_result=SQ_execute_query(SQ_NOSTORE, tr->sql_connection, query->str);
// fprintf(stderr, "D: query (com new): %s\n", query->str);
}
/* Commit the transaction for the MAIN tables */
/* Commit the transaction for person_role, mntner, as_set, route_set tables */
/* They require different handling because of dummies */
/* The rule is: Update: dummy->0, Insert: preserve dummy value */
/* These tables do not require deletions since we cannot have such condition (object_id==0 AND thread_id==0) */
if((tr->class_type==C_PN) || (tr->class_type==C_RO) ||
(tr->class_type==C_AS) || (tr->class_type==C_RS) ||
(tr->class_type==C_MT)){
/* Process the rows updated/touched */
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);
sql_result=SQ_execute_query(SQ_NOSTORE, tr->sql_connection, query->str);
// fprintf(stderr, "D: query (com new): %s\n", query->str);
}
if((tr->class_type==C_IR) && (tr->save)){ // Some special processing for inet_rtr - not good, but...
/* Delete old records from the table */
g_string_sprintf(query, "DELETE FROM inet_rtr WHERE thread_id=0 AND object_id=%ld", tr->object_id);
sql_result=SQ_execute_query(SQ_NOSTORE, tr->sql_connection, query->str);
// fprintf(stderr, "D: query (del old): %s\n", query->str);
g_string_sprintf(query, "UPDATE inet_rtr SET thread_id=0, local_as='%s' WHERE object_id=%ld", (char *)tr->save, tr->object_id);
sql_result=SQ_execute_query(SQ_NOSTORE, tr->sql_connection, query->str);
// fprintf(stderr, "D: query (com new): %s\n", query->str);
}
else {
/* Process all other MAIN tables for updates/inserts and person_role, mntner, as_set, route_set tables for rows inserts */
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);
sql_result=SQ_execute_query(SQ_NOSTORE, tr->sql_connection, query->str);
// fprintf(stderr, "D: query (com new): %s\n", query->str);
}
/* for tables that might be affected by dummies */
for(j=0; j < tr->ndummy; j++)// if dummies have been created
for (i=1; tables[tr->class_type][i] != NULL; i++) {
g_string_sprintf(query, "UPDATE %s SET thread_id=0 WHERE object_id=%ld ", tables[tr->class_type][i], tr->dummy_id[j]);
sql_result=SQ_execute_query(SQ_NOSTORE, tr->sql_connection, query->str);
// fprintf(stderr, "D: query (com new DUMMY): %s\n", query->str);
}
// Update radix tree for route and inetnum
if(tr->standalone==0) { // only if server
if((tr->class_type==C_RT) && (tr->save)) {
if (RX_get_tree( &mytree, RIPE_REG, IP_V4, RX_FAM_RT) != RX_OK )err=-1;
else
err=update_rx_bin(RX_OPER_CRE, mytree, (rx_bin_data_t *)tr->save, tr->object_id);
}
if((tr->class_type==C_IN) && (tr->save)) {
if (RX_get_tree( &mytree, RIPE_REG, IP_V4, RX_FAM_IN) != RX_OK ) err=-1;
else
err=update_rx_inum(RX_OPER_CRE, mytree, (rx_inum_data_t *)tr->save, tr->object_id);
}
}
/* Unlock all tables */
g_string_sprintf(query, "UNLOCK TABLES ");
sql_result=SQ_execute_query(SQ_NOSTORE, tr->sql_connection, query->str);
//fprintf(stderr,"%s\n", query->str);
g_string_free(query, TRUE);
return(err);
} /* commit() */
/* Function to fill data for radix tree */
static void get_rx_data(void *element_data, void *tr_ptr)
/* [<][>][^][v][top][bottom][index][help] */
{
Attribute_t *attr = element_data;
Transaction_t *tr = (Transaction_t *)tr_ptr;
unsigned int prefix, prefix_length;
unsigned int begin_in, end_in;
static rx_bin_data_t rx_bin_data;
static rx_inum_data_t rx_inum_data;
switch(attr->type) {
case A_RT:
expand_rt(attr->value, &prefix, &prefix_length);
save_rx_pref(&rx_bin_data, prefix, prefix_length);
tr->save = (void *)&rx_bin_data;
break;
case A_IN:
convert_in(attr->value, &begin_in, &end_in);
save_rx_rang(&rx_inum_data, begin_in, end_in);
tr->save = (void *)&rx_inum_data;
break;
default:
break;
}
}
/******************************************************
*int delete(Transaction_t *tr)
* Delete the object
*
*****************************************************/
int delete(Transaction_t *tr)
/* [<][>][^][v][top][bottom][index][help] */
{
SQ_result_set_t * sql_result;
rx_tree_t *mytree;
GString *query;
int err=0;
int i;
int num;
long sequence_id;
long ref_id;
long num_rec;
long timestamp;
char sobject_id[STR_M];
char *sql_str;
/* Check for referential integrity of deletion */
sprintf(sobject_id, "%ld", tr->object_id);
switch(tr->class_type){
case C_PN:
case C_RO:
if(tr->dummy==1)break;
for (i=0; t_ipn[i] != NULL; i++) {
sql_str= get_field_str(tr, "COUNT(*)", t_ipn[i], "pe_ro_id", sobject_id, NULL);
if(sql_str) {
num_rec = atol(sql_str); free(sql_str);
ref_id=tr->object_id;
if(num_rec==1) {
sql_str= get_field_str(tr, "object_id", t_ipn[i], "pe_ro_id", sobject_id, NULL);
if(sql_str) {
ref_id = atol(sql_str); free(sql_str);
} else {
tr->succeeded=0; tr->error |= ERROR_U_DBS; break;
}
}
if((num_rec>1) || (ref_id!=tr->object_id)) {
g_string_sprintfa(tr->error_script,"E[%d][%ld]:ref integrity: %s\n" ,ERROR_U_OBJ, num_rec, t_ipn[i]);
tr->succeeded=0; tr->error |= ERROR_U_OBJ;
}
} else {
tr->succeeded=0; tr->error |= ERROR_U_DBS;
}
}
break;
case C_MT:
if(tr->dummy==1)break;
for (i=0; t_imt[i] != NULL; i++) {
sql_str= get_field_str(tr, "COUNT(*)", t_imt[i], "mnt_id", sobject_id, NULL);
if(sql_str) {
num_rec = atol(sql_str); free(sql_str);
ref_id=tr->object_id;
if(num_rec==1) {
sql_str= get_field_str(tr, "object_id", t_imt[i], "mnt_id", sobject_id, NULL);
if(sql_str) {
ref_id = atol(sql_str); free(sql_str);
} else {
tr->succeeded=0; tr->error |= ERROR_U_DBS; break;
}
}
if((num_rec>1) || (ref_id!=tr->object_id)) {
g_string_sprintfa(tr->error_script,"E[%d][%ld]:ref integrity: %s\n" ,ERROR_U_OBJ, num_rec, t_imt[i]);
tr->succeeded=0; tr->error |= ERROR_U_OBJ;
}
} else {
tr->succeeded=0; tr->error |= ERROR_U_DBS;
}
}
break;
case C_RS:
case C_AS:
sql_str= get_field_str(tr, "COUNT(*)", "member_of", "set_id", sobject_id, NULL);
if(sql_str) {
num_rec = atol(sql_str); free(sql_str);
ref_id=tr->object_id;
if(num_rec==1) {
sql_str= get_field_str(tr, "object_id", "member_of", "set_id", sobject_id, NULL);
if(sql_str) {
ref_id = atol(sql_str); free(sql_str);
} else {
tr->succeeded=0; tr->error |= ERROR_U_DBS; break;
}
}
if((num_rec>1) || (ref_id!=tr->object_id)) {
g_string_sprintfa(tr->error_script,"E[%d][%ld]:ref integrity: %s\n" ,ERROR_U_OBJ, num_rec, "member_of");
tr->succeeded=0; tr->error |= ERROR_U_OBJ;
}
} else {
tr->succeeded=0; tr->error |= ERROR_U_DBS;
}
break;
default:
break;
}
if(tr->succeeded==0){
return(-1);
}
if ((query = g_string_sized_new(STR_XXL)) == NULL){
fprintf(stderr, "E: cannot allocate gstring\n");
tr->succeeded=0;
tr->error|=ERROR_U_MEM;
return(ERROR_U_MEM);
}
/* Lock all relevant tables */
if(tr->class_type==C_IR) g_string_sprintf(query, "LOCK TABLES inet_rtr WRITE");
else g_string_sprintf(query, "LOCK TABLES %s WRITE,", tables[tr->class_type][0]);
for (i=1; tables[tr->class_type][i] != NULL; i++)
g_string_sprintfa(query, " %s WRITE,", tables[tr->class_type][i]);
for (i=TAB_START; tables[tr->class_type][i] != NULL; i++)
g_string_sprintfa(query, " %s WRITE,", tables[tr->class_type][i]);
g_string_sprintfa(query, " last WRITE, history WRITE ");
sql_result=SQ_execute_query(SQ_NOSTORE, tr->sql_connection, query->str);
//fprintf(stderr,"%s\n", query->str);
for (i=TAB_START; tables[tr->class_type][i] != NULL; i++) {
g_string_sprintf(query, "DELETE FROM %s WHERE object_id=%ld ", tables[tr->class_type][i], tr->object_id);
sql_result=SQ_execute_query(SQ_NOSTORE, tr->sql_connection, query->str);
// fprintf(stderr, "D: query (delete): %s\n", query->str);
}
/* process tables differently for these type of objects (because of dummy). Table should appear first */
if((tr->class_type==C_PN) || (tr->class_type==C_RO) ||
(tr->class_type==C_AS) || (tr->class_type==C_RS) ||
(tr->class_type==C_MT)) {
g_string_sprintf(query, "DELETE FROM %s WHERE object_id=%ld ", tables[tr->class_type][0], tr->object_id);
sql_result=SQ_execute_query(SQ_NOSTORE, tr->sql_connection, query->str);
// fprintf(stderr, "D: query (delete): %s\n", query->str);
}
if(tr->class_type==C_IR){
/* Don't forget about inet_rtr, since we haven't included it in the Tables. */
g_string_sprintf(query, "DELETE FROM inet_rtr WHERE object_id=%ld ", tr->object_id);
sql_result=SQ_execute_query(SQ_NOSTORE, tr->sql_connection, query->str);
// fprintf(stderr, "D: query (delete): %s\n", query->str);
}
else {
/* Process the MAIN tables (they appear first in the table list */
g_string_sprintf(query, "DELETE FROM %s WHERE object_id=%ld ", tables[tr->class_type][0], tr->object_id);
sql_result=SQ_execute_query(SQ_NOSTORE, tr->sql_connection, query->str);
// fprintf(stderr, "D: query (delete): %s\n", query->str);
}
g_string_sprintf(query, "INSERT history "
"SELECT 0, object_id, sequence_id, timestamp, object_type, object "
"FROM last "
"WHERE object_id=%ld ", tr->object_id);
//fprintf(stderr, "D: copying entry into the history table\n %s\n", query->str);
sql_result=SQ_execute_query(SQ_STORE, tr->sql_connection, query->str);
num = mysql_affected_rows(tr->sql_connection);
if (sql_result)SQ_free_result(sql_result);
if ((num == -1) || (num == 0)) {
fprintf(stderr, "E ERROR!<perform_update>: INSERT history failed:[%d][%s]\n", num, query->str);
tr->succeeded=0;
tr->error |=ERROR_U_DBS;
}
// get sequence number
sequence_id = get_sequence_id(tr);
// insert new version into the last
timestamp=time(NULL);
g_string_sprintf(query, "UPDATE last SET object='' WHERE object_id=%ld ", tr->object_id);
sql_result=SQ_execute_query(SQ_STORE, tr->sql_connection, query->str);
num = mysql_affected_rows(tr->sql_connection);
if (sql_result)SQ_free_result(sql_result);
if ((num == -1) || (num == 0)) {
fprintf(stderr, "E ERROR!<perform_update>: UPDATE last failed: [%d][%s]\n", num, query->str);
tr->succeeded=0;
tr->error |= ERROR_U_DBS;
}
// Do more in the forest
// Update radix tree for route and inetnum
if(tr->standalone==0) { // only if server
g_slist_foreach((tr->object)->attributes, get_rx_data, tr);
if((tr->class_type==C_RT) && (tr->save)) {
if (RX_get_tree( &mytree, RIPE_REG, IP_V4, RX_FAM_RT) != RX_OK ) err=-1;
else err=update_rx_bin(RX_OPER_DEL, mytree, (rx_bin_data_t *)tr->save, tr->object_id);
}
if((tr->class_type==C_IN) && (tr->save)) {
if (RX_get_tree( &mytree, RIPE_REG, IP_V4, RX_FAM_IN) != RX_OK ) err=-1;
else err=update_rx_inum(RX_OPER_DEL, mytree, (rx_inum_data_t *)tr->save, tr->object_id);
}
}
/* Unlock all tables */
g_string_sprintf(query, "UNLOCK TABLES ");
sql_result=SQ_execute_query(SQ_NOSTORE, tr->sql_connection, query->str);
//fprintf(stderr,"%s\n", query->str);
g_string_free(query, TRUE);
return(err);
} /* delete() */