Source File modules/ud/ud_core.c

    1    | /***************************************
    2    |
    3    |   $Revision: 1.40 $
    4    |
    5    |   Core functions for update lower layer
    6    |
    7    |   Status: NOT REVUED, NOT TESTED
    8    |
    9    |  Author(s):       Chris Ottrey, Andrei Robachevsky
    10   |
    11   |   ******************/ /******************
    12   |   Modification History:
    13   |         andrei (17/01/2000) Created.
    14   |   ******************/ /******************
    15   |   Copyright (c) 2000                              RIPE NCC
    16   |
    17   |   All Rights Reserved
    18   |
    19   |   Permission to use, copy, modify, and distribute this software and its
    20   |   documentation for any purpose and without fee is hereby granted,
    21   |   provided that the above copyright notice appear in all copies and that
    22   |   both that copyright notice and this permission notice appear in
    23   |   supporting documentation, and that the name of the author not be
    24   |   used in advertising or publicity pertaining to distribution of the
    25   |   software without specific, written prior permission.
    26   |
    27   |   THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
    28   |   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
    29   |   AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
    30   |   DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
    31   |   AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    32   |   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    33   |  ***************************************/
    34   | #include "ud.h"
    35   | #include "ud_int.h"
    36   | #include "ud_tr.h"
    37   |
    38   | #include <sys/types.h>
    39   | #include <signal.h>
    40   | #include <time.h>
    41   |
    42   | static int perform_update(Transaction_t *tr);
    43   |
    44   | static int perform_create(Transaction_t *tr);
    45   |
    46   | static void each_attribute_process(void *element_data, void *tr_ptr);
    47   |
    48   | static void update_attr(Attribute_t *attr, Transaction_t *tr);
    49   |
    50   | static int create_dummy(Attribute_t *attr, Transaction_t *tr);
    51   |
    52   | static int auth_member_of(Attribute_t *attr, Transaction_t *tr);
    53   |
    54   | /***************************************************
    55   | * char *s_split(char *line)                        *
    56   | *                                                  *
    57   | * Consequently returns words of the 'line'         *
    58   | * When there are no words it returns NULL          *
    59   | * You need to retreive all words !                 *
    60   | *                                                  *
    61   | * NB This function damages 'line' replacing        *
    62   | * whitespace with '\0'                             *
    63   | * *************************************************/
    64   | #define ATTR_DELIMITERS " ,"
    65   |
    66   |
    67   | /**********************************************************
    68   | * Attribute expansion/conversion functions                *
    69   | ***********************************************************/
    70   | /* Convert ifaddr attribute into numbers */
    71   | er_ret_t convert_if(char *avalue, unsigned int *pif_address)
    72   | {
    73   | char *delim=avalue;
    74   | ip_addr_t ip_addr;
    75   | er_ret_t ret;
    76   |
    77   | /*XXX  if ((delim=index(avalue, ' '))!=NULL) *delim='\0'; */
    78   |   while((*delim) && (!isspace((int)*delim))) {
    79   |       delim++;
    80   |   }
    81   |   *delim='\0';
    82   |
    83   |   ret=IP_addr_a2v4(avalue, &ip_addr,  pif_address );
    84   |   return(ret);
    85   | }
    86   |
    87   |
    88   | /* Convert refer attribute. Free host after use ! */
    89   | char *convert_rf(char *avalue, int *type, int *port)
    90   | {
    91   | char *delim, *token;
    92   | char buff[STR_M];
    93   | char *host;
    94   |
    95   |   host=NULL;
    96   |   strcpy(buff, avalue);
    97   |   g_strchug(buff);
    98   | /*XXX  delim=index(buff, ' '); */
    99   |   delim=buff;
    100  |   while((*delim) && (!isspace((int)*delim))) {
    101  |       delim++;
    102  |   }
    103  |   if (*delim)*delim='\0'; else return(NULL);
    104  |   delim++;
    105  |
    106  | /* convert the type      */
    107  |   if(g_strcasecmp(buff, S_RIPE)==0)*type=RF_RIPE;
    108  |    else if(g_strcasecmp(buff, S_INTERNIC)==0)*type=RF_INTERNIC;
    109  |     else if(g_strcasecmp(buff, S_SIMPLE)==0)*type=RF_SIMPLE;
    110  |      else if(g_strcasecmp(buff, S_CLIENTADDERSS)==0)*type=RF_CLIENTADDRESS;
    111  |
    112  |   token=delim;
    113  |   g_strchug(token);
    114  | /*XXX  delim=index(token, ' '); */
    115  |   delim=token;
    116  |   while((*delim) && (!isspace((int)*delim))) {
    117  |       delim++;
    118  |   }
    119  |
    120  |   if(*delim){
    121  |    *delim='\0';
    122  |    delim++;
    123  |   }
    124  | /* convert the hostname      */
    125  |   host = g_strdup(token);
    126  |
    127  | /* convert port number      */
    128  |   if(*delim){
    129  |     token=delim;
    130  |     *port = atoi(token);
    131  |     if (*port==0) *port=RF_DEF_PORT; /* default port number*/
    132  |   } else *port=RF_DEF_PORT;
    133  |   return(host);
    134  | }
    135  |
    136  |
    137  | /* Convert AS# into integer */
    138  | static int convert_as(char *as)
    139  | {
    140  | char *ptr;
    141  |  ptr=as;
    142  |  while((*ptr) && (!isdigit((int)*ptr))) ptr++;
    143  |  return(atoi(ptr));
    144  | }
    145  |
    146  | /* Convert AS range (AS4321 - AS5672) into numbers */
    147  | int convert_as_range(const char *as_range, int *begin, int *end)
    148  | {
    149  | char *range;
    150  | char *token;
    151  |
    152  |   range=g_strdup(as_range);
    153  |   token=range;
    154  |   *begin=convert_as(strsep(&token, "-"));
    155  |   *end=convert_as(token);
    156  |   free(range);
    157  |   return(0);
    158  | }
    159  |
    160  | /* Convert time in ASCII format (19991224) into time_t unix time */
    161  | time_t convert_time(char *asc_time)
    162  | {
    163  | struct tm tm;
    164  | char buf[STR_S];
    165  | char *ptr;
    166  |
    167  |
    168  |   bzero(&tm, sizeof(tm));
    169  |
    170  |   strncpy(buf, asc_time, 4); ptr=buf+4; *ptr='\0';
    171  |   tm.tm_year = atoi(buf) - 1900;
    172  |
    173  |   strncpy(buf, (asc_time+4), 2); ptr=buf+2; *ptr='\0';
    174  |   tm.tm_mon = atoi(buf) - 1;
    175  |
    176  |   strncpy(buf, (asc_time+6), 2); ptr=buf+2; *ptr='\0';
    177  |   tm.tm_mday = atoi(buf);
    178  |
    179  |   return(mktime(&tm));
    180  |
    181  | }
    182  |
    183  |
    184  | /************************************************************
    185  | *  char *get_set_name()                                     *
    186  | *                                                           *
    187  | * Returns set name for the specified object class           *
    188  | *                                                           *
    189  | * **********************************************************/
    190  | static char *get_set_name(C_Type_t class_type)
    191  | {
    192  |  switch(class_type){
    193  |   case C_RT:   return("route_set");
    194  |   case C_AN:   return("as_set");
    195  |   case C_IR:   return("rtr_set");
    196  |   default:     return(NULL);
    197  |  }
    198  | }
    199  |
    200  |
    201  | /************************************************************
    202  | * long get_object_id()                                      *
    203  | * Queries the database for an object.                       *
    204  | * For constructing a query uses each_primary_key_select()   *
    205  | *                                                           *
    206  | * Returns:                                                  *
    207  | * >0 - object exists, returns object_id                     *
    208  | * 0  - object does not exist                                *
    209  | * -1 - error (f.e. more than one object with the same PK)   *
    210  | * Error code is stored in tr->error                         *
    211  | *                                                           *
    212  | * **********************************************************/
    213  | long get_object_id(Transaction_t *tr)
    214  | {
    215  | Object_t *obj;
    216  | SQ_result_set_t *sql_result;
    217  | SQ_row_t *sql_row;
    218  | char *sql_str;
    219  | long object_id=0;
    220  | int sql_err;
    221  |
    222  |  obj=tr->object;
    223  |
    224  |  if ((tr->query = g_string_sized_new(STR_XL)) == NULL){
    225  |   ER_perror(FAC_UD, UD_MEM, "cannot allocate gstring\n");
    226  |   tr->succeeded=0;
    227  |   tr->error |= ERROR_U_MEM;
    228  |   die;
    229  |  }
    230  |
    231  | /* compose query */
    232  |  g_string_sprintf(tr->query, "SELECT object_id FROM %s WHERE",DF_get_class_sql_table(obj->type));
    233  |  /* add all primary keys */
    234  |  g_slist_foreach(obj->attributes, ud_each_primary_key_select, tr);
    235  |  /* truncate the last ' AND '*/
    236  |  g_string_truncate(tr->query, (tr->query->len) - 4);
    237  |
    238  | /* execute query */
    239  |  ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s [%s]", UD_TAG, tr->query->str);
    240  |  sql_err=SQ_execute_query(tr->sql_connection, tr->query->str, &sql_result);
    241  |
    242  | /* in case of an error copy error code and return */
    243  |  if(sql_err) {
    244  |    ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), tr->query->str);
    245  |    tr->succeeded=0;
    246  |    tr->error |= ERROR_U_DBS;
    247  |    die;
    248  |  }
    249  |  g_string_free(tr->query, TRUE);
    250  |
    251  | /* Fetch the row */
    252  |  if ((sql_row = SQ_row_next(sql_result)) != NULL) {
    253  | /* Object exists */
    254  | #define OBJECT_ID 0
    255  |    sql_str = SQ_get_column_string(sql_result, sql_row, OBJECT_ID);
    256  |    if (sql_str != NULL) {
    257  |      object_id = atol(sql_str);
    258  |      free(sql_str);
    259  |    }
    260  |
    261  | /* We must process all the rows of the result */
    262  | /* otherwise we'll have them as part of the next qry */
    263  |    while ( (sql_row = SQ_row_next(sql_result)) != NULL) object_id=-1;
    264  |  } else
    265  |       object_id=0;  /* object does not exist*/
    266  |
    267  |  SQ_free_result(sql_result);
    268  |  return(object_id);
    269  | }
    270  |
    271  | /************************************************************
    272  | * get_minmax_id()                                           *
    273  | *                                                           *
    274  | * Returns the min or max ID of the table                    *
    275  | *                                                           *
    276  | * Returns:                                                  *
    277  | *  min (max=0) or max (max=1) ID                            *
    278  | *  -1 in case of an error                                   *
    279  | *                                                           *
    280  | *                                                           *
    281  | *************************************************************/
    282  | long get_minmax_id(SQ_connection_t *sql_connection, char *id_name, char *tbl_name, int max)
    283  | {
    284  | char query[STR_M];
    285  | SQ_result_set_t *sql_result;
    286  | SQ_row_t *sql_row;
    287  | char *sql_str;
    288  | long id;
    289  | char *minmax;
    290  | int sql_err;
    291  |
    292  | if(max==1)minmax="max"; else minmax="min";
    293  |
    294  |  sprintf(query, "SELECT %s(%s) FROM %s ", minmax, id_name, tbl_name);
    295  |
    296  |  ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s [%s]", UD_TAG, query);
    297  |  sql_err = SQ_execute_query(sql_connection, query, &sql_result);
    298  |
    299  |  if(sql_err) {
    300  |     ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(sql_connection), query);
    301  |     die;
    302  |  }
    303  |
    304  |
    305  |  if ((sql_row = SQ_row_next(sql_result)) != NULL) {
    306  | 	sql_str = SQ_get_column_string(sql_result, sql_row, 0);
    307  |
    308  |      /* We must process all the rows of the result,*/
    309  |      /* otherwise we'll have them as part of the next qry */
    310  | 	while ( (sql_row = SQ_row_next(sql_result)) != NULL) {
    311  | 	  ER_perror(FAC_UD, UD_SQL, "duplicate PK [%s]\n", query);
    312  | 	  die;
    313  | 	  if(sql_str)free(sql_str); sql_str=NULL;
    314  | 	}
    315  |  }
    316  |  else sql_str=NULL;
    317  |
    318  |  if(sql_result){ SQ_free_result(sql_result); sql_result=NULL; }
    319  |
    320  |  if(sql_str) {
    321  |   id = atol(sql_str);
    322  |   free(sql_str);
    323  |  }
    324  |  else id=-1;
    325  |
    326  |  return(id);
    327  |
    328  | }
    329  |
    330  |
    331  | /************************************************************
    332  | * get_qresult_str()                                         *
    333  | *                                                           *
    334  | * Returns string containing query result                    *
    335  | *                                                           *
    336  | *                                                           *
    337  | * Returns:                                                  *
    338  | *  String containing the result.Needs to be freed after use *
    339  | *  NULL in case of an error                                 *
    340  | *  - SQL error                                              *
    341  | *  - if query returns more than one string (row)            *
    342  | *                                                           *
    343  | *************************************************************/
    344  | char *get_qresult_str(SQ_connection_t *sql_connection, char *query)
    345  | {
    346  | SQ_result_set_t *sql_result;
    347  | SQ_row_t *sql_row;
    348  | char *sql_str;
    349  | int sql_err;
    350  |
    351  |
    352  |  ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s [%s]", UD_TAG, query);
    353  |  sql_err=SQ_execute_query(sql_connection, query, &sql_result);
    354  |
    355  |  if(sql_err) {
    356  |     ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(sql_connection), query);
    357  |     die;
    358  |  }
    359  |
    360  |
    361  |  if ((sql_row = SQ_row_next(sql_result)) != NULL) {
    362  | 	sql_str = SQ_get_column_string(sql_result, sql_row, 0);
    363  |
    364  |      /* We must process all the rows of the result,*/
    365  |      /* otherwise we'll have them as part of the next qry */
    366  | 	while ( (sql_row = SQ_row_next(sql_result)) != NULL) {
    367  | 	  ER_perror(FAC_UD, UD_SQL, "duplicate PK [%s]\n", query);
    368  | 	  if(sql_str)free(sql_str); sql_str=NULL;
    369  | 	}
    370  |  }
    371  |  else sql_str=NULL;
    372  |
    373  |  SQ_free_result(sql_result);
    374  |  return(sql_str);
    375  | }
    376  |
    377  |
    378  |
    379  | /************************************************************
    380  | * get_field_str()                                           *
    381  | *                                                           *
    382  | * Returns string containing the field.                      *
    383  | *  field - field name to be retrieved                       *
    384  | *  ref_tbl_name - name of the table containing the field    *
    385  | *  ref_name - reference name                                *
    386  | *  attr_value - reference value                             *
    387  | *  condition - additional condition ( f.e. 'AND dummy=0'    *
    388  | *                                                           *
    389  | * Returns:                                                  *
    390  | *  String containing the field. Needs to be freed after use *
    391  | *  NULL in case of an error                                 *
    392  | *                                                           *
    393  | *************************************************************/
    394  | char *get_field_str(SQ_connection_t *sql_connection, char *field,
    395  | 			   char *ref_tbl_name, char *ref_name,
    396  | 			   char * attr_value, char *condition)
    397  | {
    398  | char query[STR_L];
    399  |
    400  |  sprintf(query, "SELECT %s FROM %s "
    401  |                 "WHERE %s='%s' ",
    402  | 		field, ref_tbl_name, ref_name, attr_value);
    403  |  if (condition)strcat(query, condition);
    404  |
    405  |  return( get_qresult_str(sql_connection, query));
    406  |
    407  | }
    408  |
    409  | /************************************************************
    410  | * long get_sequence_id(Transaction_t *tr)
    411  | * >0 - success
    412  | * -1 - sql error
    413  | *
    414  | * **********************************************************/
    415  |
    416  | long get_sequence_id(Transaction_t *tr)
    417  | {
    418  | char *sql_str;
    419  | char str_id[STR_M];
    420  | long sequence_id=-1;
    421  |
    422  |
    423  |   sprintf(str_id, "%ld", tr->object_id);
    424  |   sql_str= get_field_str(tr->sql_connection, "sequence_id", "last", "object_id", str_id, NULL);
    425  |   if(sql_str) {
    426  |        	  sequence_id = atol(sql_str);
    427  |        	  free(sql_str);
    428  |   }
    429  |
    430  |   return(sequence_id);
    431  |
    432  | }
    433  |
    434  |
    435  | /************************************************************
    436  | * long get_ref_id(char *ref_tbl_name, char *ref_name, char * attr_value)
    437  | * >0 - success
    438  | * -1 - sql error
    439  | *
    440  | * **********************************************************/
    441  |
    442  | static long get_ref_id(Transaction_t *tr, char *ref_tbl_name, char *ref_name, char * attr_value, char *condition)
    443  | {
    444  | char *sql_str;
    445  | long ref_id=-1;
    446  |
    447  | 	sql_str= get_field_str(tr->sql_connection, "object_id", ref_tbl_name, ref_name, attr_value, condition);
    448  | 	if(sql_str) {
    449  | 		 ref_id = atol(sql_str);
    450  | 		 free(sql_str);
    451  | 	}
    452  | 	return(ref_id);
    453  | }
    454  |
    455  |
    456  | /************************************************************
    457  | * int isdummy()
    458  | *
    459  | * Returns 1 if the object in question is a dummy,
    460  | * otherwise returns 0.
    461  | *
    462  | * In case of error:
    463  | * -1 - sql error or object does not exist
    464  | *
    465  | ***********************************************************/
    466  |
    467  | int isdummy(Transaction_t *tr)
    468  | {
    469  | char *sql_str;
    470  | char str_id[STR_M];
    471  | int object_type=-1;
    472  |
    473  |   sprintf(str_id, "%ld", tr->object_id);
    474  |   sql_str= get_field_str(tr->sql_connection, "object_type", "last", "object_id", str_id, NULL);
    475  |   if(sql_str) {
    476  |        	  object_type = atoi(sql_str);
    477  |        	  free(sql_str);
    478  |   }
    479  |
    480  |   if (object_type==-1) {
    481  |    ER_perror(FAC_UD, UD_SQL, "cannot get object type\n");
    482  |    die;
    483  |   }
    484  |   if (object_type==DUMMY_TYPE) return(1);
    485  |   else return(0);
    486  |
    487  | }
    488  |
    489  | /* it may be either a legacy name reference, or a nic-handle  */
    490  | /* we rely on other parsers/syntax checkers, so no surprises  */
    491  | /* thus, the check is simple - if there is a space - not a nh */
    492  | static int isnichandle(char *name)
    493  | {
    494  |  char *delim;
    495  |
    496  | /*XXX if(index(name, ' ')) return(0);
    497  |  else return(1);	*/
    498  |  delim=name;
    499  |  while((*delim) && (!isspace((int)*delim))) {
    500  |       delim++;
    501  |  }
    502  |  if(*delim) return(0);
    503  |  else return(1);
    504  | }
    505  |
    506  |
    507  | /************************************************************
    508  | * process_reverse_domain()                                  *
    509  | *                                                           *
    510  | * Tries to insert additional data for reverse domains       *
    511  | * This data includes prefix and perfix length for reverse   *
    512  | * delegation block. It is stored in inaddr_arpa table for   *
    513  | * IPv4 and ip6int table for IPv6 address spaces             *
    514  | *                                                           *
    515  | * Returns:                                                  *
    516  | * 0  success                                                *
    517  | * -1 sql error                                              *
    518  | *                                                           *
    519  | *************************************************************/
    520  |
    521  | static int process_reverse_domain(Transaction_t *tr,
    522  | 				  ip_prefix_t *prefptr,
    523  | 				  int op)
    524  | {
    525  |   unsigned prefix, prefix_length; /* ipv4 */
    526  |   ip_v6word_t msb, lsb;          /* ipv6 */
    527  |   char query[STR_L];
    528  |   int num;
    529  |   int sql_err;
    530  |
    531  |
    532  |   if( IP_pref_b2_space(prefptr) == IP_V4 ) {  /* ipv4 */
    533  |     if(op==0) { /* insert record */
    534  |       IP_revd_b2v4(prefptr, &prefix, &prefix_length);
    535  |       sprintf(query, "INSERT INTO inaddr_arpa SET thread_id=%d, object_id=%ld, prefix=%u, prefix_length=%d ",
    536  | 	      tr->thread_ins, tr->object_id, prefix, prefix_length);
    537  |     }
    538  |     else {
    539  |       /* update record */
    540  |       sprintf(query, "UPDATE inaddr_arpa SET thread_id=%d WHERE object_id=%ld ",
    541  | 	      tr->thread_upd, tr->object_id);
    542  |     }
    543  |   }
    544  |   else { /* ipv6 */
    545  |     if(op==0) { /* insert record */
    546  |       IP_revd_b2v6(prefptr, &msb, &lsb, &prefix_length);
    547  |       sprintf(query, "INSERT INTO ip6int SET thread_id=%d, object_id=%ld, msb='%llu', lsb='%llu', prefix_length=%d ",
    548  | 	      tr->thread_ins, tr->object_id, msb, lsb, prefix_length);
    549  |     }
    550  |     else {
    551  |       /* update record */
    552  |       sprintf(query, "UPDATE ip6int SET thread_id=%d WHERE object_id=%ld ",
    553  | 	      tr->thread_upd, tr->object_id);
    554  |     }
    555  |   }
    556  |
    557  |   ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s [%s]", UD_TAG, query);
    558  |   sql_err = SQ_execute_query(tr->sql_connection, query, (SQ_result_set_t **)NULL);
    559  |   num = SQ_get_affected_rows(tr->sql_connection);
    560  |
    561  |   /* Check for errors */
    562  |   if (sql_err) {
    563  |    ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query);
    564  |    die;
    565  |   }
    566  |   /* If nothing was affected then WHERE clause returned nothing - DB error */
    567  |   if(num == 0) {
    568  |    ER_perror(FAC_UD, UD_SQL, "insert inaddr had no effect [%s]\n", query);
    569  |    die;
    570  |   }
    571  |   return(0);
    572  | }
    573  |
    574  | #define insert_reverse_domain(tr, pr) process_reverse_domain(tr, pr, 0)
    575  | #define update_reverse_domain(tr, pr) process_reverse_domain(tr, pr, 1)
    576  |
    577  |
    578  | /************************************************************
    579  | * auth_member_of()                                          *
    580  | *                                                           *
    581  | * Function that checks the authorization for membership     *
    582  | * (i.e. if the object is authorized to be a memeber by      *
    583  | * mbrs-by-ref attribute of the set is refers by member-of   *
    584  | * attribute).                                               *
    585  | * First checks if 'mbrs-by-ref: ANY'                        *
    586  | * If not then checks that maintner referenced by            *
    587  | * mbrs-by-ref attribute of the set is the one in mnt-by.    *
    588  | *                                                           *
    589  | * Returns:                                                  *
    590  | * 0  success                                                *
    591  | * 1  not allowed                                            *
    592  | * -1 SQL error                                              *
    593  | *                                                           *
    594  | *************************************************************/
    595  | static int auth_member_of(Attribute_t *attr, Transaction_t *tr)
    596  | {
    597  | GString *query;
    598  | char *set_name;
    599  | char *qresult;
    600  |
    601  | /* Check if set has mbrs_by_ref==ANY
    602  |    In such case mbrs_by_ref.mnt_id==0
    603  | */
    604  |
    605  |  if ((query = g_string_sized_new(STR_XL)) == NULL){
    606  |   tr->succeeded=0;
    607  |   tr->error |= ERROR_U_MEM;
    608  |   ER_perror(FAC_UD, UD_MEM, "cannot allocate gstring\n");
    609  |   die;
    610  |  }
    611  |
    612  |  set_name = get_set_name(tr->class_type);
    613  | /* ER_dbg_va(FAC_UD, ASP_UD_OBJ, "%s set name retrieved: %s\n", UD_TAG, set_name);	*/
    614  |
    615  | /* Check if the set protects itself with mbrs-by-ref attribute */
    616  |    g_string_sprintf(query,"SELECT COUNT(*) FROM mbrs_by_ref, %s "
    617  |    		          "WHERE mbrs_by_ref.object_id=%s.object_id "
    618  | 			  "AND %s.%s='%s' ",
    619  | 			  set_name, set_name, set_name, set_name, attr->value);
    620  |
    621  |    qresult = get_qresult_str(tr->sql_connection, query->str);
    622  |    /* should be '0' if there is no mbrs-by-ref attribute */
    623  |    if (strcmp(qresult, "0")==0){
    624  | 	   /* there is no mbrs-by-ref attribute - so we cannot go ahead */
    625  | 	   ER_dbg_va(FAC_UD, ASP_UD_OBJ, "[%ld] membership by reference is not allowed (no mbrs-by-ref) [%d:%s]", tr->transaction_id, attr->type, attr->value);
    626  | 	   g_string_free(query, TRUE);
    627  |            return(1);
    628  |    }
    629  |    else free(qresult);
    630  |
    631  | /* Check if membership is protected by the keyword "ANY" */
    632  | /* There is a dummy mntmer object in the database corresponding to "ANY" */
    633  | /* Its object_id==0 */
    634  | /* EXAMPLE:
    635  |
    636  |    SELECT route_set.object_id
    637  |    FROM   mbrs_by_ref, route_set
    638  |    WHERE  mbrs_by_ref.object_id=route_set.object_id
    639  |    AND    route_set.route_set=<setname>
    640  |    AND    mbrs_by_ref.mnt_id=0
    641  | */
    642  |     g_string_sprintf(query,"SELECT %s.object_id FROM mbrs_by_ref, %s "
    643  |                            "WHERE mbrs_by_ref.object_id=%s.object_id "
    644  | 		           "AND %s.%s='%s' AND mbrs_by_ref.mnt_id=0 ",
    645  | 			   set_name, set_name, set_name, set_name, set_name, attr->value);
    646  |
    647  |     qresult = get_qresult_str(tr->sql_connection, query->str);
    648  |   /* if such record exists - go ahead */
    649  |     if(qresult) {
    650  | 	free(qresult);
    651  | 	g_string_free(query, TRUE);
    652  |         return(0);
    653  |     }
    654  |
    655  | /* Now check if our mnt_by belongs to mbrs_by_ref list of the set */
    656  | /* we search only mnt_by.thread_id!=0 to check against new/updated mnt-by attribute */
    657  |     g_string_sprintf(query, "SELECT mbrs_by_ref.object_id FROM %s, mbrs_by_ref, mnt_by "
    658  |  			    "WHERE mbrs_by_ref.mnt_id=mnt_by.mnt_id "
    659  |     			    "AND mnt_by.object_id=%ld "
    660  |     			    "AND %s.object_id=mbrs_by_ref.object_id "
    661  |     			    "AND %s.%s='%s' "
    662  |     			    "AND ( mnt_by.thread_id=%d OR mnt_by.thread_id=%d ) ",
    663  |     			    set_name, tr->object_id, set_name, set_name, set_name, attr->value, tr->thread_upd, tr->thread_ins);
    664  |
    665  |     qresult = get_qresult_str(tr->sql_connection, query->str);
    666  |     /* If our mntner is listed (non-empty result)  membership is authorized */
    667  |     if (qresult) {
    668  | 	 free(qresult);g_string_free(query, TRUE);
    669  | 	 return(0);
    670  |     } else {
    671  | 	 ER_dbg_va(FAC_UD, ASP_UD_OBJ, "[%ld] membership by reference is not autorized [%d:%s]", tr->transaction_id, attr->type, attr->value);
    672  | 	 g_string_free(query, TRUE);
    673  | 	 return(1);
    674  |     }
    675  |  }/* auth_member_of()  */
    676  |
    677  |
    678  | /************************************************************
    679  | * create_dummy()                                            *
    680  | *                                                           *
    681  | * Function that creates a dummy object (that is one that    *
    682  | * is referenced from an object but does not                 *
    683  | * exist in the database).                                   *
    684  | * Dummy object exists only in relevant main and 'last'      *
    685  | * tables. Its creation is controlled by tr->dummy_allowed.  *
    686  | * Queries for the dummies are defined in Dummy[] array.     *
    687  | *                                                           *
    688  | * Returns:                                                  *
    689  | * 0  success                                                *
    690  | * 1  no rf integrity and dummy not allowed                  *
    691  | * -1 SQL error                                              *
    692  | *                                                           *
    693  | *************************************************************/
    694  | static int create_dummy(Attribute_t *attr, Transaction_t *tr)
    695  | {
    696  | const char *query_fmt;
    697  | long dummy_id;
    698  | char query[STR_L];
    699  | int result=0;
    700  | char *set_name;
    701  | char *p_name;
    702  | int query_type;
    703  | long timestamp;
    704  | char str_id[STR_M];
    705  | gchar *attr_value=NULL;
    706  | int sql_err;
    707  | char *token=NULL;
    708  |
    709  |   query_fmt = DF_get_dummy_query(attr->type);
    710  |   if (strcmp(query_fmt, "") == 0) {
    711  |      ER_perror(FAC_UD, UD_BUG, "empty query string\n");
    712  |      die;
    713  |   }
    714  |
    715  |   /* We allow creating dummy sets in any mode */
    716  |   /* For others attributes return if we are in protected mode */
    717  |   if ((attr->type!=A_MO) &&  (!IS_DUMMY_ALLOWED(tr->mode))) return(1);
    718  |
    719  |   /* Insert dummy in the last table */
    720  |   /* Calculate the object_id - should be max+1 */
    721  |   dummy_id = SQ_get_max_id(tr->sql_connection, "object_id", "last") +1;
    722  |  /* Record dummy's object_id, it'll be needed in commit/rollback */
    723  |   tr->dummy_id[tr->ndummy]=dummy_id; tr->ndummy++;
    724  |
    725  |   /* Update the TR for crash recovery */
    726  |   /* If we crash before actually creating an entry in last */
    727  |   /* there should be no harm - later in rollback we will just try to delete nonexistent object */
    728  |   TR_update_dummy(tr);
    729  |
    730  |   sprintf(str_id, "%ld", tr->object_id);
    731  |   timestamp=time(NULL);
    732  |   sprintf(query, "INSERT INTO last SET thread_id=%d, object_id=%ld, timestamp=%ld, object_type=%d, object='DUMMY for %s'",
    733  |                   tr->thread_ins, dummy_id, timestamp, DUMMY_TYPE, str_id);
    734  |
    735  |   ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s [%s]", UD_TAG, query);
    736  |   sql_err = SQ_execute_query(tr->sql_connection, query, (SQ_result_set_t **)NULL);
    737  |
    738  |   /* Check for errors */
    739  |   if (sql_err) {
    740  |    ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query);
    741  |    die;
    742  |   }
    743  |
    744  |
    745  |   /* compose the query */
    746  |   query_type=DF_get_dummy_query_type(attr->type);
    747  |   switch (query_type) {
    748  |
    749  | 	 /* person_role */
    750  | 	 case UD_AX_PR:
    751  |     	      sprintf(query, query_fmt, tr->thread_ins, dummy_id, attr->value, DUMMY_TYPE);
    752  | 	      break;
    753  |
    754  | 	 /* maintner */
    755  | 	 case UD_AX_MT:
    756  | 	      sprintf(query, query_fmt, tr->thread_ins, dummy_id, attr->value, DUMMY_TYPE);
    757  | 	      break;
    758  |
    759  |          /* as_set, route_set */
    760  | 	 case UD_AX_MO:
    761  | 	      set_name = get_set_name(tr->class_type);
    762  | 	      sprintf(query, query_fmt, set_name, tr->thread_ins, dummy_id, set_name, attr->value);
    763  | 	      break;
    764  |
    765  | 	 default:
    766  | 	      ER_perror(FAC_UD, UD_BUG, "query not defined for this type of attribute[%d]\n", attr->type);
    767  | 	      die;
    768  |               break;
    769  |   }
    770  |
    771  |   ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s [%s]", UD_TAG, query);
    772  |   sql_err = SQ_execute_query(tr->sql_connection, query, (SQ_result_set_t **)NULL);
    773  |   if (sql_err) {
    774  |    ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query);
    775  |    die;
    776  |   }
    777  |
    778  |   /* for legacy person/role reference (without nic-handle) create records in names table */
    779  |   if( (query_type == UD_AX_PR) && (!isnichandle (attr->value)) ){
    780  |    /* parse the names */
    781  |     /*ER_dbg_va(FAC_UD, ASP_UD_OBJ, "%s adding names for dummy\n", UD_TAG);*/
    782  |     query_fmt = DF_get_insert_query(A_PN);
    783  |     attr_value = g_strdup(attr->value);
    784  |     token = attr_value;
    785  |     while((p_name=strsep(&token, " \t"))){
    786  | 	if (*p_name != '\0'){
    787  | 		sprintf(query, query_fmt, tr->thread_ins, dummy_id, DUMMY_TYPE, p_name);
    788  | 		ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s [%s]", UD_TAG, query);
    789  | 		sql_err = SQ_execute_query(tr->sql_connection, query, (SQ_result_set_t **)NULL);
    790  | 		if (sql_err)
    791  | 		 if(SQ_errno(tr->sql_connection) != ER_DUP_ENTRY) {
    792  | 		  ER_perror(FAC_UD, UD_SQL, "insert dummy names:%s[%s]\n", SQ_error(tr->sql_connection), query);
    793  | 		  result=-1;
    794  | 		 }
    795  | 	}
    796  |     }
    797  |     free(attr_value);
    798  |   }
    799  |  return(result);
    800  | }
    801  |
    802  | /************************************************************
    803  | * update_attr()                                             *
    804  | *                                                           *
    805  | * Function that updates an attribute if it already exists.  *
    806  | * Called from each_attribute_proces() function if it        *
    807  | * cannot insert the row.                                    *
    808  | * Queries for the attributes are defined in Update[] array. *
    809  | *                                                           *
    810  | * Returns: Nothing. Error code is stored in tr->error.      *
    811  | *                                                           *
    812  | *************************************************************/
    813  | static void update_attr(Attribute_t *attr, Transaction_t *tr)
    814  | {
    815  | int num;
    816  | const char *query_fmt;
    817  | char *set_name;
    818  | unsigned int if_address;
    819  | char * rf_host;
    820  | int rf_port, rf_type;
    821  | char *a_value;
    822  | int sq_info[3];
    823  | char * condition;
    824  | char *sq_error;
    825  | char query[STR_XL];
    826  | ip_prefix_t dn_pref;
    827  | int sql_err;
    828  | char *token;
    829  | char *mu_mntner;
    830  |
    831  |
    832  | /* It may be needed to update second attribute stored in the main table, like inetnum, filter-set, etc. */
    833  |  if((tr->load_pass!=0)&&(DF_get_update_query_type(attr->type)!=UD_MA_U2)) return;
    834  |
    835  | /*	ER_dbg_va(FAC_UD, ASP_UD_OBJ, "%s updating attribute...\n", UD_TAG);*/
    836  |
    837  |    /* Do some additional processing for reverse domains */
    838  |    /* XXX Later we will implement this under UD_MA_DN case */
    839  |    if ((attr->type == A_DN) && (IP_revd_a2b(&dn_pref, attr->value)==IP_OK)) {
    840  |      if(update_reverse_domain(tr, &dn_pref) !=0 ){
    841  |        tr->error|=ERROR_U_DBS;
    842  |        tr->succeeded=0;
    843  |        g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:%s\n" ,
    844  | 			 ERROR_U_DBS, attr->type, attr->value, SQ_error(tr->sql_connection));
    845  |      }
    846  |    }
    847  |
    848  |    /* get query format string */
    849  |    query_fmt =  DF_get_update_query(attr->type);
    850  |
    851  |    if (strcmp(query_fmt, "") == 0) return;
    852  |
    853  |    switch (DF_get_update_query_type(attr->type)) {
    854  |          case UD_MAIN_: sprintf(query, query_fmt, tr->thread_upd, tr->object_id);
    855  |                         break;
    856  | 	 case UD_MA_PR:
    857  | 	 		sprintf(query, query_fmt, tr->thread_upd, tr->class_type, tr->object_id);
    858  | 			break;
    859  | 	 case UD_MA_U2: /* save the new value of the attribute for commit*/
    860  |                   /* this is necessary for filter(filter-set), netname (inet?num), */
    861  | 		  /* local-as(inet-rtr) attributes, as they are another field in the record */
    862  | 		        if((tr->load_pass != 0)){
    863  | 		      /* for fast loader we need to update the field as we have no commit */
    864  | 		          sprintf(query, query_fmt, DF_get_class_sql_table(tr->class_type), 0, attr->value, tr->object_id);
    865  | 		        }
    866  | 		        else {
    867  |             	         tr->save=g_strdup(attr->value);
    868  | /*            	         ER_dbg_va(FAC_UD, ASP_UD_OBJ, "%s u2 saved [%s]\n", UD_TAG, tr->save); */
    869  |                          /* update TR for crash recovery */
    870  | 			 TR_update_save(tr);
    871  |             	         return;
    872  |             	        }
    873  | 			break;
    874  | 	 case UD_AX_PR:
    875  |                         /* This is for non-conformant admin-c, etc.*/
    876  |                         a_value=attr->value;
    877  | 	 		if(strlen(attr->value)>MAX_NIC_HDL)*(attr->value + MAX_NIC_HDL)='\0';
    878  |
    879  | 	 		if (!IS_DUMMY_ALLOWED(tr->mode))condition="AND dummy=0 "; else condition=NULL;
    880  | 	 		sprintf(query, query_fmt, tr->thread_upd, tr->object_id,
    881  | 	 			get_ref_id(tr, "person_role", "nic_hdl", attr->value, condition));
    882  | 	 		break;
    883  | 	 case UD_AX_MT:
    884  | 	 		if (!IS_DUMMY_ALLOWED(tr->mode))condition="AND dummy=0 "; else condition=NULL;
    885  | 	 		sprintf(query, query_fmt, tr->thread_upd, tr->object_id,
    886  | 	 			get_ref_id(tr, "mntner", "mntner", attr->value, condition));
    887  | 	 		break;
    888  |          case UD_AX_MU: /* for mnt_routes table*/
    889  |    	                a_value=g_strdup(attr->value);
    890  |                         token = a_value;
    891  |                         mu_mntner=strsep(&token, " \t");
    892  |                        	if (!IS_DUMMY_ALLOWED(tr->mode))condition="AND dummy=0 "; else condition=NULL;
    893  | 	 		sprintf(query, query_fmt, tr->thread_upd, tr->object_id,
    894  | 	 			get_ref_id(tr, "mntner", "mntner", mu_mntner, condition));
    895  | 			free(a_value);
    896  | 			break;
    897  | 	 case UD_AX_MO:
    898  | 			set_name = get_set_name(tr->class_type);
    899  | /*	    	      ER_dbg_va(FAC_UD, ASP_UD_OBJ, "%s retrieved set name: %s\n", UD_TAG, set_name);*/
    900  | 			if (!IS_DUMMY_ALLOWED(tr->mode))condition="AND dummy=0 "; else condition=NULL;
    901  | 			sprintf(query, query_fmt, tr->thread_upd, tr->object_id,
    902  | 					get_ref_id(tr, set_name, set_name, attr->value, condition));
    903  | 			break;
    904  |     	 case UD_AX_MR:
    905  |       			if ((g_strcasecmp(attr->value, "ANY")==0))
    906  |       		 	sprintf(query, query_fmt, tr->thread_upd, tr->object_id,
    907  |       		 	 	get_ref_id(tr, "mntner", "mntner", "ANY",NULL));
    908  |       			else {
    909  |       		 	 if (!IS_DUMMY_ALLOWED(tr->mode))condition="AND dummy=0 "; else condition=NULL;
    910  |       		 	 sprintf(query, query_fmt, tr->thread_upd, tr->object_id,
    911  |       		 	 	get_ref_id(tr, "mntner", "mntner", attr->value, condition));
    912  |       		 	}
    913  | 			break;
    914  | 	 case UD_LEAF_:
    915  | 	 		sprintf(query, query_fmt, tr->thread_upd, tr->object_id, attr->value);
    916  | 			break;
    917  | 	 case UD_LF_IF:
    918  | 		/* Convert ascii ip -> numeric one */
    919  |       	                convert_if(attr->value, &if_address);
    920  | 			sprintf(query, query_fmt, tr->thread_upd, tr->object_id, if_address);
    921  |     			break;
    922  | 	 case UD_LF_RF:
    923  | 			rf_host=convert_rf(attr->value, &rf_type, &rf_port);
    924  | 			if(rf_host == NULL) {
    925  | 				tr->error|=ERROR_U_OBJ;
    926  |   	                        tr->succeeded=0;
    927  |   	                        g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:incorrect attribute value\n" ,
    928  | 				ERROR_U_OBJ, attr->type, attr->value);
    929  | 				return;
    930  | 			}
    931  | 			else {
    932  | 			        sprintf(query, query_fmt, tr->thread_upd, tr->object_id, rf_type, rf_host, rf_port);
    933  | 			        free(rf_host);
    934  | 			}
    935  | 			break;
    936  |   	 case UD_LF_AY:
    937  |                   	sprintf(query, query_fmt, tr->thread_upd, tr->object_id, convert_time(attr->value));
    938  |                    	break;
    939  | 	   default:
    940  | 			tr->error|=ERROR_U_BUG;
    941  | 			tr->succeeded=0;
    942  | 			g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:no update qry\n" ,ERROR_U_BUG, attr->type, attr->value);
    943  | 			ER_perror(FAC_UD, UD_BUG, "query not defined for this type of attribute:[%d:%s]\n", attr->type, attr->value);
    944  | 			die;
    945  |     			break;
    946  |         }
    947  |    /* Execute the query */
    948  |     ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s [%s]", UD_TAG, query);
    949  |     sql_err = SQ_execute_query(tr->sql_connection, query, (SQ_result_set_t **)NULL);
    950  |     if(sql_err) { /* an error occured*/
    951  |      /* Error - copy the error condition and return */
    952  |         sq_error=SQ_error(tr->sql_connection);
    953  | 	ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", sq_error, query);
    954  | 	tr->error|=ERROR_U_DBS;
    955  | 	tr->succeeded=0;
    956  | 	g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:%s\n" ,ERROR_U_DBS, attr->type, attr->value, sq_error);
    957  | 	die;
    958  |     }
    959  |     else {
    960  |      /* Query OK */
    961  |       num = SQ_get_affected_rows(tr->sql_connection);
    962  |       if(num == 0) { /* check for duplicates*/
    963  |   	SQ_get_info(tr->sql_connection, sq_info); /* UPDATE ... SET*/
    964  |   	if ((sq_info[SQL_DUPLICATES]==0) && (sq_info[SQL_MATCHES]==0)) {
    965  |   	/* Condition with zero duplicates and matches may occur when the object is a dummy */
    966  |   	/* and we are running in protected mode ( dummies are not allowed, tr->dummy==0). */
    967  |   	/* In such case we will append "AND dummy=0" to the query, which won't */
    968  |   	/* return a match if the object in question is a dummy */
    969  |   	  ER_inf_va(FAC_UD, ASP_UD_UPDLOG, "[%ld] dummy prevents update: [%s]", tr->transaction_id, query);
    970  |   	  tr->error|=ERROR_U_OBJ;
    971  |   	  tr->succeeded=0;
    972  |   	  g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:dummy update\n" ,ERROR_U_OBJ, attr->type, attr->value);
    973  |   	} /* else duplicate entry - silently drop it  */
    974  |       }
    975  |       /* For member_of attribute we need to check membership claim in protected mode */
    976  |       if ((attr->type == A_MO) && (!IS_DUMMY_ALLOWED(tr->mode))){
    977  | 	  if(auth_member_of(attr, tr)!=0){
    978  | 	  tr->error|=ERROR_U_AUT;
    979  | 	  tr->succeeded=0;
    980  | 	  ER_inf_va(FAC_UD, ASP_UD_UPDLOG, "[%ld] membership by reference is not allowed [%d:%s]", tr->transaction_id, attr->type, attr->value);
    981  | 	  g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:membership not allowed\n" ,ERROR_U_AUT, attr->type, attr->value);
    982  | 	}
    983  |       }
    984  |     }
    985  | return;
    986  | }/*  update_attr()  */
    987  |
    988  |
    989  | /************************************************************
    990  | * each_attribute_proces()                                   *
    991  | *                                                           *
    992  | * Main function that processes object attributes one by one.*
    993  | * Called from g_slist_foreach() function.                   *
    994  | * First it tries to insert an attribute.                    *
    995  | * If an error it assumes that attribute is already in       *
    996  | * a table and calls update_attr() to update it.             *
    997  | * Queries for the attributes are defined in Insert[] array. *
    998  | *                                                           *
    999  | * Returns: Nothing. Error code is stored in tr->error.      *
    1000 | *                                                           *
    1001 | *************************************************************/
    1002 | static void each_attribute_process(void *element_data, void *tr_ptr)
    1003 | {
    1004 | int num;
    1005 | const char *query_fmt;
    1006 | int query_type;
    1007 | int do_query;
    1008 | Attribute_t *attr = element_data;
    1009 | Transaction_t *tr = (Transaction_t *)tr_ptr;
    1010 | unsigned int prefix, prefix_length, if_address;
    1011 | unsigned int begin_in, end_in;
    1012 | ip_v6word_t  high, low;
    1013 |
    1014 | int begin_as, end_as;
    1015 | char query[STR_XL];
    1016 | char * set_name;
    1017 | char * rf_host; /* needs to be freed after use*/
    1018 | int rf_type, rf_port;
    1019 | char *a_value;
    1020 | int sq_info[3];
    1021 | char *mu_mntner;
    1022 | int dummy_err;
    1023 | char *sq_error;
    1024 | ip_prefix_t dn_pref;
    1025 | int sql_err;
    1026 | int res;
    1027 | char *token;
    1028 |
    1029 | /* we still want to continue to collect all possible errors*/
    1030 | /*  if(tr->succeeded == 0) return; */
    1031 |
    1032 |  /* To switch off querying for some types of attributes */
    1033 |   do_query=1;
    1034 |
    1035 |  /* Determine the query type */
    1036 |   query_type=DF_get_insert_query_type(attr->type);
    1037 |
    1038 | /* For loadind pass #1 we need to process only main tables */
    1039 |   if(tr->load_pass==1){
    1040 | 	switch(query_type) {
    1041 | 	 case UD_MAIN_:
    1042 | 	 case UD_MA_U2:
    1043 | 	 case UD_MA_PR:
    1044 | 	 case UD_MA_RT:
    1045 | 	 case UD_MA_IN:
    1046 | 	 case UD_MA_I6:
    1047 | 	 case UD_MA_OR:
    1048 | 	 case UD_MA_AK:
    1049 | 	 		break;
    1050 | 	 default:	return;	/* return for other than MAIN tables*/
    1051 | 	}
    1052 |   }
    1053 |
    1054 |     query_fmt = DF_get_insert_query(attr->type);
    1055 |
    1056 | /* return if no query is defined for this attribute */
    1057 |   if (strcmp(query_fmt, "") == 0) return;
    1058 |
    1059 |  /* compose the query depending on the attribute */
    1060 |   switch (query_type) {
    1061 |    case UD_MAIN_: /* for MAIN tables */
    1062 |    		if (ACT_UPDATE(tr->action)) do_query=0;
    1063 |     		else
    1064 |     		sprintf(query, query_fmt, tr->thread_ins, tr->object_id, attr->value);
    1065 |     		break;
    1066 |    case UD_MA_OR: /* for the origin attribute */
    1067 |    		if (ACT_UPDATE(tr->action)) do_query=0;
    1068 |     		else {
    1069 | 		  sprintf(query, query_fmt, tr->thread_ins, attr->value, tr->object_id);
    1070 | 		  tr->action |= TA_UPD_RX;
    1071 | 		  RP_pack_set_orig(attr->type, tr->packptr, attr->value);
    1072 | 		}
    1073 |     		break;
    1074 |    case UD_MA_PR: /* for person_role table*/
    1075 |    		if (ACT_UPDATE(tr->action)) do_query=0;
    1076 |    		else
    1077 |    		 sprintf(query, query_fmt, tr->thread_ins, tr->class_type, tr->object_id,  attr->value);
    1078 |
    1079 |    		/* check if we need to update NHR */
    1080 |     		if (ACT_UPD_NHR(tr->action)) {
    1081 | 		 /* Check if we can allocate it */
    1082 | 		  res = NH_check(tr->nh, tr->sql_connection);
    1083 | 		  if(res == -1) { /* we cannot allocate this NIC handle (DB error) */
    1084 | 		     tr->succeeded=0;
    1085 | 		     tr->error |= ERROR_U_DBS;
    1086 | 		     g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:cannot allocate nic-handle\n", ERROR_U_DBS, attr->type, attr->value);
    1087 | 		     ER_perror(FAC_UD, UD_SQL, "cannot allocate nic hdl[%s]\n", attr->value);
    1088 |                      die;
    1089 |                   }
    1090 |                   else
    1091 |                   if(res == 0) { /* we cannot allocate this NIC handle (full space or ID in use) */
    1092 | 		    tr->succeeded=0;
    1093 | 		    tr->error |= ERROR_U_OBJ;
    1094 | 		    g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:nic-handle already in use\n", ERROR_U_OBJ, attr->type, attr->value);
    1095 | 		    return;
    1096 | 		  }
    1097 | 		}
    1098 |     		break;
    1099 |    case UD_MA_RT: /* for route table*/
    1100 |     		if (ACT_UPDATE(tr->action)) do_query=0;
    1101 |     		else {
    1102 |                   tr->action |= TA_UPD_RX;
    1103 |     		  RP_pack_set_pref4(attr->type, attr->value, tr->packptr, &prefix, &prefix_length);
    1104 | 		  /*ER_dbg_va(FAC_UD, ASP_UD_OBJ, "%s route: %u/%u\n", UD_TAG, prefix, prefix_length);     		*/
    1105 | 		  sprintf(query, query_fmt, tr->thread_ins,
    1106 | 			  tr->object_id, prefix, prefix_length);
    1107 | 	    	}
    1108 |     		break;
    1109 |    case UD_MA_IN: /* for inetnum table*/
    1110 |     		if (ACT_UPDATE(tr->action)) do_query=0;
    1111 |     		else {
    1112 | 		  tr->action |= TA_UPD_RX;
    1113 |     		  RP_pack_set_rang(attr->type, attr->value, tr->packptr, &begin_in, &end_in);
    1114 | 		  /* XXX error handling ? */
    1115 | 		  sprintf(query, query_fmt, tr->thread_ins, tr->object_id, begin_in, end_in);
    1116 | 		}
    1117 |     		break;
    1118 |    case UD_MA_I6: /* for inet6num table*/
    1119 |                 if (ACT_UPDATE(tr->action)) do_query=0;
    1120 |     		else {
    1121 |     		  tr->action |= TA_UPD_RX;
    1122 | 		  RP_pack_set_pref6(attr->type, attr->value, tr->packptr, &high, &low, &prefix_length);
    1123 | 		  /* XXX error handling ? */
    1124 | 		  sprintf(query, query_fmt, tr->thread_ins, tr->object_id, high, low, prefix_length);
    1125 | 		}
    1126 |     		break;
    1127 |    case UD_MA_U2: /* This is actually an update - go to update_attr - this is more natural */
    1128 |                  do_query=0;
    1129 |             	break;
    1130 |    case UD_MA_AK: /* for as_block table*/
    1131 |    		if (ACT_UPDATE(tr->action)) do_query=0;
    1132 |    		else {
    1133 |    		  convert_as_range(attr->value, &begin_as, &end_as);
    1134 | 		  sprintf(query, query_fmt, tr->thread_ins, tr->object_id, begin_as, end_as);
    1135 |    		}
    1136 |    		break;
    1137 |    case UD_AUX__: /* for AUX tables*/
    1138 |     		if((attr->type==A_AC) || (attr->type==A_TC) || (attr->type==A_ZC))
    1139 |     		 if(strlen(attr->value)>MAX_NIC_HDL)*(attr->value + MAX_NIC_HDL)='\0';
    1140 |
    1141 |     		sprintf(query, query_fmt, tr->thread_ins, tr->object_id, tr->class_type, attr->value);
    1142 |     		if(!IS_DUMMY_ALLOWED(tr->mode))strcat(query, " AND dummy=0 ");
    1143 |     		break;
    1144 |    case UD_AX_MO: /* for member_of table*/
    1145 | 		set_name = get_set_name(tr->class_type);
    1146 | /*    		ER_dbg_va(FAC_UD, ASP_UD_OBJ, "%s retrieved set name: %s\n", UD_TAG, set_name);*/
    1147 |     		sprintf(query, query_fmt, tr->thread_ins,
    1148 | 	    	 tr->object_id, set_name, tr->class_type, set_name, set_name, set_name, attr->value);
    1149 |     		break;
    1150 |    case UD_AX_MR: /* for mbrs_by_ref table*/
    1151 |       		if ((g_strcasecmp(attr->value, "ANY")==0))
    1152 |       		 sprintf(query, query_fmt, tr->thread_ins, tr->object_id, tr->class_type, "ANY");
    1153 |       		else
    1154 |       		 sprintf(query, query_fmt, tr->thread_ins, tr->object_id, tr->class_type, attr->value);
    1155 | 		break;
    1156 |    case UD_AX_MU: /* for mnt_routes table*/
    1157 |    		a_value=g_strdup(attr->value);
    1158 | 		token = a_value;
    1159 | 		mu_mntner=strsep(&token, " \t");
    1160 |    		sprintf(query, query_fmt, tr->thread_ins, tr->object_id, tr->class_type, mu_mntner);
    1161 |    		free(a_value);
    1162 |    		if (!IS_DUMMY_ALLOWED(tr->mode))strcat(query, " AND dummy=0 ");
    1163 |    		break;
    1164 |    case UD_LEAF_: /* for LEAF tables*/
    1165 |     		sprintf(query, query_fmt, tr->thread_ins, tr->object_id, attr->value);
    1166 |     		break;
    1167 |    case UD_LF_OT: /* for LEAF tables containing object_type field*/
    1168 |    		sprintf(query, query_fmt, tr->thread_ins, tr->object_id, tr->class_type, attr->value);
    1169 |    		break;
    1170 |    case UD_LF_AT: /* check PGPKEY. If yes - check the existence of key-cert.*/
    1171 |       		if(!IS_DUMMY_ALLOWED(tr->mode)){
    1172 |       		 if(strncmp("PGPKEY", attr->value, 6)==0) {
    1173 |       		   if(get_ref_id(tr, "key_cert", "key_cert", attr->value, NULL)<=0) {
    1174 |       		    ER_inf_va(FAC_UD, ASP_UD_UPDLOG, "[%ld] no key-cert object[%s]", tr->transaction_id, attr->value);
    1175 |       		    tr->error|=ERROR_U_OBJ;
    1176 |       		    tr->succeeded=0;
    1177 |       		    g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:no key-cert object\n" ,ERROR_U_OBJ, attr->type, attr->value);
    1178 |       		    return;
    1179 |       	           }
    1180 |       		 }
    1181 |       		}
    1182 |       		sprintf(query, query_fmt, tr->thread_ins, tr->object_id, tr->class_type, attr->value);
    1183 |       		break;
    1184 |    case UD_LF_IF: /* for ifaddr tables*/
    1185 |     		/* Convert ascii ip -> numeric one*/
    1186 |     		convert_if(attr->value, &if_address);
    1187 | 		sprintf(query, query_fmt, tr->thread_ins, tr->object_id, if_address);
    1188 |     		break;
    1189 |    case UD_LF_RF: /* for refer table*/
    1190 |     		rf_host=convert_rf(attr->value, &rf_type, &rf_port);
    1191 | 		if(rf_host == NULL) {
    1192 | 				tr->error|=ERROR_U_OBJ;
    1193 |   	                        tr->succeeded=0;
    1194 |   	                        g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:incorrect attribute value\n" ,
    1195 | 				ERROR_U_OBJ, attr->type, attr->value);
    1196 | 				return;
    1197 | 		}
    1198 | 		else {
    1199 |     		                sprintf(query, query_fmt, tr->thread_ins, tr->object_id, rf_type, rf_host, rf_port);
    1200 |     		                free(rf_host);
    1201 | 		}
    1202 |     		break;
    1203 |    case UD_LF_AY: /* for auth_override table*/
    1204 |    		sprintf(query, query_fmt, tr->thread_ins, tr->object_id, convert_time(attr->value));
    1205 |    		break;
    1206 |     	default:
    1207 |                 tr->succeeded=0;
    1208 |                 tr->error |= ERROR_U_BUG;
    1209 |                 g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:query not defined for the attribute\n" ,ERROR_U_BUG, attr->type, attr->value);
    1210 | 		ER_perror(FAC_UD, UD_BUG, "query not defined for this type of attribute:[%d:%s]\n", attr->type, attr->value);
    1211 |                 die;
    1212 |     		break;
    1213 |   }
    1214 |
    1215 |  /* Make the query. For primary keys go straight to updates if we are updating the object */
    1216 |   if(do_query){
    1217 |    ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s [%s]", UD_TAG, query);
    1218 |    sql_err = SQ_execute_query(tr->sql_connection, query, (SQ_result_set_t **)NULL);
    1219 |   }
    1220 |   else {
    1221 |    update_attr(attr, tr);
    1222 |    return;
    1223 |   }
    1224 |
    1225 |   if (sql_err)  {
    1226 |   /* we received an error */
    1227 |    if(SQ_errno(tr->sql_connection) == ER_DUP_ENTRY){ /* Only error "Duplicate entry" may be considered*/
    1228 |   	if (ACT_UPDATE(tr->action)) { /* In update mode this is common (so actually not an error)*/
    1229 |   		update_attr(attr, tr);
    1230 |   		return;
    1231 |   	}
    1232 |      /* Otherwise this is a duplicate attribute, just ignore it */
    1233 |      /* In the future if we are more stringent, checks may be added here */
    1234 |    }
    1235 |    else { /* Other errors reveal a database/server problem*/
    1236 |         sq_error=SQ_error(tr->sql_connection);
    1237 |         tr->error|=ERROR_U_DBS;
    1238 |         tr->succeeded=0;
    1239 | 	ER_perror(FAC_UD, UD_BUG, "%s[%s]\n", sq_error, query);
    1240 |         g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:%s\n" ,ERROR_U_DBS, attr->type, attr->value, sq_error);
    1241 | 	die;
    1242 |    }
    1243 |   } /* if error occured */
    1244 |   else {
    1245 |  /* If the query was successful */
    1246 |    num = SQ_get_affected_rows(tr->sql_connection);
    1247 |    if(num>0){ /* this is OK*/
    1248 |  /* Do some additional processing for member_of attribute  */
    1249 | 	if ((attr->type == A_MO) && (!IS_DUMMY_ALLOWED(tr->mode))){
    1250 | /*		ER_dbg_va(FAC_UD, ASP_UD_OBJ, "%s need to auth membership\n", UD_TAG);*/
    1251 | 		if(auth_member_of(attr, tr)!=0){
    1252 | 		 tr->error|=ERROR_U_AUT;
    1253 | 		 tr->succeeded=0;
    1254 | 		 ER_inf_va(FAC_UD, ASP_UD_UPDLOG, "[%ld] membership not allowed [%d:%s]", tr->transaction_id, attr->type, attr->value);
    1255 | 		 g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:membership not allowed\n" ,ERROR_U_AUT, attr->type, attr->value);
    1256 | 		}
    1257 | 	}
    1258 | 	else
    1259 | 	  /* Do some additional processing for reverse zones domains */
    1260 | 	  if ((attr->type == A_DN)
    1261 | 	      && IP_revd_a2b(&dn_pref, attr->value)==IP_OK ) {
    1262 |
    1263 | 	    if(insert_reverse_domain(tr, &dn_pref) != 0 ) {
    1264 | 		tr->error|=ERROR_U_DBS;
    1265 | 		tr->succeeded=0;
    1266 | 		ER_perror(FAC_UD, UD_SQL, "cannot insert inverse domain:[%d:%s]\n", attr->type, attr->value);
    1267 | 		die;
    1268 | 	    }
    1269 | 	    else {
    1270 | 	      /* save data for the radix tree update */
    1271 | 	      tr->action |= TA_UPD_RX;
    1272 | 	      RP_pack_set_revd(attr->type, attr->value, tr->packptr);
    1273 | 	    }
    1274 | 	  }
    1275 |         return;
    1276 |    }
    1277 |    if(num == 0) {
    1278 | /* this could be an empty update or a null select */
    1279 |   	SQ_get_info(tr->sql_connection, sq_info);
    1280 |   	if (sq_info[SQL_DUPLICATES]>0) {
    1281 | 	/* INSERT ... SELECT ... affected 0 rows, but there is 1 duplicate */
    1282 | 	/* which means that we already have such record in the table */
    1283 | 	/* this indicates that this is actually an update - update this attribute */
    1284 |   		if (sq_info[SQL_DUPLICATES]>1) {
    1285 |   			tr->error|=ERROR_U_DBS;
    1286 |   			tr->succeeded=0;
    1287 | 			ER_perror(FAC_UD, UD_SQL, "too many duplicates:[%d:%s]\n", attr->type, attr->value);
    1288 |   			die;
    1289 |   		}
    1290 |   		update_attr(attr, tr);
    1291 |   	}
    1292 |   	else {
    1293 | 	/* this is an emty SELECT because there is no referred object */
    1294 | 	/* try to create dummy and repeat the original query*/
    1295 |
    1296 | /*		ER_dbg_va(FAC_UD, ASP_UD_OBJ, "%s no ref. integrity. Trying to create dummy\n", UD_TAG);*/
    1297 |
    1298 | 		dummy_err = create_dummy(attr, tr);
    1299 | 		if (dummy_err == 0) {
    1300 | 		/* Dummy was created */
    1301 | 			g_string_sprintfa(tr->error_script,"W[%d][%d:%s]:dummy created\n" ,0, attr->type, attr->value);
    1302 | 			ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s [%s]", UD_TAG, query);
    1303 | 			sql_err = SQ_execute_query(tr->sql_connection, query, (SQ_result_set_t **)NULL);
    1304 | 			num = SQ_get_affected_rows(tr->sql_connection);
    1305 | 			if (sql_err) {
    1306 | 			  sq_error=SQ_error(tr->sql_connection);
    1307 | 		          ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", sq_error, query);
    1308 | 			  tr->error|=ERROR_U_DBS;
    1309 | 		          tr->succeeded=0;
    1310 | 		          g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:%s\n" ,
    1311 | 		                            ERROR_U_DBS, attr->type, attr->value, sq_error);
    1312 | 			  die;
    1313 | 		        }
    1314 | 		        if (num==0) {
    1315 | 			  ER_perror(FAC_UD, UD_SQL, "0 rows affected [%s]\n", query);
    1316 | 			  tr->error|=ERROR_U_DBS;
    1317 | 			  tr->succeeded=0;
    1318 | 			  g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:re-insert qry\n" ,
    1319 | 			                    ERROR_U_DBS, attr->type, attr->value);
    1320 | 			  die;
    1321 | 			}
    1322 | 		}
    1323 | 		else
    1324 | 		 if(dummy_err == 1) {
    1325 | 		 /* dummy not allowed */
    1326 | 		   tr->error |= ERROR_U_OBJ;
    1327 | 		   tr->succeeded=0;
    1328 | 		   g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:dummy not allowed\n" ,ERROR_U_OBJ, attr->type, attr->value);
    1329 | 		   ER_inf_va(FAC_UD, ASP_UD_UPDLOG, "[%ld] dummy not allowed [%d:%s]", tr->transaction_id, attr->type, attr->value);
    1330 | 		 }
    1331 | 		 else {
    1332 | 		 /* SQL problem */
    1333 | 		   tr->error|=ERROR_U_DBS;
    1334 | 		   tr->succeeded=0;
    1335 | 		   ER_perror(FAC_UD, UD_SQL, "dummy cannot be created [%d:%s]", attr->type, attr->value);
    1336 | 		   g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:dummy cannot be created\n" ,ERROR_U_DBS, attr->type, attr->value);
    1337 | 		   die;
    1338 | 		}
    1339 |   	}  /* RI*/
    1340 |    }/* if num == 0*/
    1341 |   } /* if the query was successful */
    1342 |
    1343 |   return;
    1344 | } /* each_attribute_process() */
    1345 |
    1346 |
    1347 |
    1348 | /************************************************************
    1349 | * ud_each_primary_key_select()                              *
    1350 | *                                                           *
    1351 | * Function that forms a query for an object (w prinary keys)*
    1352 | * Called from g_slist_foreach() function.                   *
    1353 | * Primary keys are defined in Select[] array.               *
    1354 | *                                                           *
    1355 | * Returns: Nothing.                                         *
    1356 | *                                                           *
    1357 | *************************************************************/
    1358 | void ud_each_primary_key_select(void *element_data, void *result_ptr)
    1359 | {
    1360 | Attribute_t *attr = element_data;
    1361 | Transaction_t *tr = (Transaction_t *)result_ptr;
    1362 | const char *query_fmt;
    1363 | unsigned int prefix, prefix_length;
    1364 | unsigned int begin_in, end_in;
    1365 | int begin_as, end_as;
    1366 | ip_prefix_t prefstr;
    1367 | ip_range_t  rangstr;
    1368 | ip_v6word_t i6_msb, i6_lsb;
    1369 |
    1370 |    query_fmt = DF_get_select_query(attr->type);
    1371 |   /* if tr->query == NULL, then this is a pass to fill tr->K only (used in loader 1 pass) */
    1372 |
    1373 |   if (strcmp(query_fmt, "") != 0) {
    1374 |     switch (DF_get_select_query_type(attr->type)) {
    1375 |      case UD_MAIN_:
    1376 |      		if(tr->query)g_string_sprintfa(tr->query, query_fmt, attr->value);
    1377 | 		g_string_sprintfa(tr->K, attr->value);
    1378 |     		break;
    1379 |      case UD_MA_RT:
    1380 |                 IP_pref_a2v4(attr->value, &prefstr, &prefix, &prefix_length);
    1381 |     		if(tr->query)g_string_sprintfa(tr->query, query_fmt, prefix, prefix_length);
    1382 |     		g_string_sprintfa(tr->K, attr->value);
    1383 |                 break;
    1384 |      case UD_MA_IN:
    1385 | 		IP_rang_a2v4(attr->value, &rangstr, &begin_in, &end_in);
    1386 | 		if(tr->query)g_string_sprintfa(tr->query, query_fmt, begin_in, end_in);
    1387 |     		g_string_sprintfa(tr->K, attr->value);
    1388 |                 break;
    1389 |      case UD_MA_I6:
    1390 | 		IP_pref_a2v6(attr->value, &prefstr, &i6_msb, &i6_lsb, &prefix_length);
    1391 | 		if(tr->query)g_string_sprintfa(tr->query, query_fmt, i6_msb, i6_lsb, prefix_length);
    1392 | 		g_string_sprintfa(tr->K, attr->value);
    1393 |     		break;
    1394 |      case UD_MA_AK:
    1395 |      		convert_as_range(attr->value, &begin_as, &end_as);
    1396 |      		if(tr->query)g_string_sprintfa(tr->query, query_fmt, begin_as, end_as);
    1397 | 		g_string_sprintfa(tr->K, attr->value);
    1398 | 		break;
    1399 |      default:
    1400 | 		ER_perror(FAC_UD, UD_BUG, "query not defined for this type of attribute:[%d:%s]\n", attr->type, attr->value);
    1401 |                 die;
    1402 |
    1403 |     	break;
    1404 |     }
    1405 |   }
    1406 | }
    1407 |
    1408 | /************************************************************
    1409 | * perform_create(const Object_t *obj, Transaction_t *tr)    *
    1410 | *                                                           *
    1411 | * Procedure for creating a new object.                      *
    1412 | * First inserts object into 'last' table and gets object_id.*
    1413 | * Then processes all attributes.                            *
    1414 | *                                                           *
    1415 | * Returns: tr->succeeded: >0 success, 0 - error             *
    1416 | * Error code is stored in tr->error.                        *
    1417 | *                                                           *
    1418 | *************************************************************/
    1419 | static int perform_create(Transaction_t *tr)
    1420 | {
    1421 |  Object_t *obj;
    1422 |  char *str;
    1423 |  GString *query;
    1424 |  long timestamp;
    1425 |  int sql_err;
    1426 | // long object_id;
    1427 |
    1428 |
    1429 |  if ((query = g_string_sized_new(STR_XL)) == NULL){
    1430 |   tr->succeeded=0;
    1431 |   tr->error |= ERROR_U_MEM;
    1432 |   ER_perror(FAC_UD, UD_MEM, "cannot allocate gstring\n");
    1433 |   die;
    1434 |  }
    1435 |
    1436 |
    1437 |  obj=tr->object;
    1438 |
    1439 |       str = (obj->object)->str;
    1440 |       timestamp=time(NULL);
    1441 |       tr->sequence_id=1; /* we start with 1*/
    1442 |   /* Calculate the object_id - should be max+1 */
    1443 |   /* XXX we cannot use autoincrement with MyISAM tables */
    1444 |   /* XXX because they keep the max inserted id even if  */
    1445 |   /* XXX it was deleted later, thus causing gaps we don't want */
    1446 |
    1447 |       tr->object_id = SQ_get_max_id(tr->sql_connection, "object_id", "last") +1;
    1448 |       TR_update_id(tr);
    1449 |
    1450 |       g_string_sprintf(query, "INSERT INTO last SET thread_id=%d, object_id=%ld, "
    1451 |                               "timestamp=%ld, sequence_id=1, object_type=%d, object='%s', pkey='%s' ",
    1452 |       	              tr->thread_ins, tr->object_id, timestamp, tr->class_type, str, tr->K->str);
    1453 |
    1454 |       ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s [%s]", UD_TAG, query->str);
    1455 |       sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
    1456 |
    1457 |      /* Check for affected rows. One row should be affected . */
    1458 |       if (sql_err) {
    1459 |         tr->error|=ERROR_U_DBS;
    1460 |         tr->succeeded=0;
    1461 | 	ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
    1462 | 	die;
    1463 |       }
    1464 |       else {
    1465 |         g_slist_foreach(obj->attributes, each_attribute_process, tr);
    1466 |       }
    1467 |     g_string_free(query, TRUE);
    1468 |     return(tr->succeeded);
    1469 | } /* perform_create() */
    1470 |
    1471 | /************************************************************
    1472 | * perform_update(Transaction_t *tr)                         *
    1473 | *                                                           *
    1474 | * Procedure for updating (existing) object.                 *
    1475 | * First processes all attributes.                           *
    1476 | * Then saves previous object in 'history' and updates       *
    1477 | * 'last' table.                                             *
    1478 | *                                                           *
    1479 | * Returns: tr->succeeded: >0 success, 0 - error             *
    1480 | * Error code is stored in tr->error.                        *
    1481 | *                                                           *
    1482 | *************************************************************/
    1483 | static int perform_update(Transaction_t *tr)
    1484 | {
    1485 | Object_t *obj;
    1486 | char *str;
    1487 | GString *query;
    1488 | int num;
    1489 | long sequence_id;
    1490 | long timestamp;
    1491 | char *sq_error;
    1492 | int sql_err;
    1493 |
    1494 |
    1495 |    obj=tr->object;
    1496 |    /* get sequence number */
    1497 |
    1498 |    sequence_id = get_sequence_id(tr);
    1499 |    if(sequence_id==-1) {
    1500 |       tr->error|=ERROR_U_DBS;
    1501 |       tr->succeeded=0;
    1502 |       ER_perror(FAC_UD, UD_SQL, "cannot get sequence_id");
    1503 |       die;
    1504 |    }
    1505 |    else tr->sequence_id=sequence_id; /* save it for rollback*/
    1506 |    /* Update TR record */
    1507 |    TR_update_id(tr);
    1508 |
    1509 |   /* process each attribute one by one */
    1510 |   g_slist_foreach(obj->attributes, each_attribute_process, tr);
    1511 |
    1512 |   /* If we've already failed or this is fast load - just return */
    1513 |   if((tr->succeeded == 0) || (tr->load_pass != 0)) return(tr->succeeded);
    1514 |
    1515 |     /* No return: thread_id=0 */
    1516 |     /* Do it only if previous transactions finished well */
    1517 |   if ((query = g_string_sized_new(STR_XL)) == NULL){
    1518 |    tr->succeeded=0;
    1519 |    tr->error |= ERROR_U_MEM;
    1520 |    ER_perror(FAC_UD, UD_MEM, "cannot allocate gstring");
    1521 |    die;
    1522 |   }
    1523 |     /* copy object to the history table */
    1524 |     g_string_sprintf(query,"INSERT history "
    1525 |                   "SELECT %d, object_id, sequence_id, timestamp, object_type, object, pkey, serial, prev_serial "
    1526 |                   "FROM last "
    1527 |                   "WHERE object_id=%ld ", tr->thread_ins, tr->object_id);
    1528 |
    1529 |     ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s [%s]", UD_TAG, query->str);
    1530 |     sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
    1531 |
    1532 |    /* Check for affected rows. One row should be affected . */
    1533 |     num = SQ_get_affected_rows(tr->sql_connection);
    1534 |     if (num < 1) {
    1535 |          tr->error|=ERROR_U_DBS;
    1536 |          tr->succeeded=0;
    1537 |          if (sql_err) {
    1538 |           sq_error=SQ_error(tr->sql_connection);
    1539 | 	  ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
    1540 | 	  die;
    1541 |          }
    1542 |          else {
    1543 | 	  ER_perror(FAC_UD, UD_SQL, "0 rows affected [%s]\n", query->str);
    1544 | 	/* This is to check that this is really could happen */
    1545 | 	  die;
    1546 |          }
    1547 | 	 g_string_free(query, TRUE);
    1548 |          return(tr->succeeded);
    1549 |     }
    1550 |
    1551 |     /* Insert new version into the last */
    1552 |
    1553 |     /* Put a timestamp */
    1554 |     str = (obj->object)->str;
    1555 |     timestamp=time(NULL);
    1556 |
    1557 | /* update last for commit/rollback */
    1558 |
    1559 |     g_string_sprintf(query, "INSERT last "
    1560 |                    "SET thread_id=%d, object_id=%ld, sequence_id=%ld, timestamp=%ld, object_type=%d, object='%s', pkey='%s' ",
    1561 |                    tr->thread_ins, tr->object_id, tr->sequence_id+1, timestamp, tr->class_type, str, tr->K->str);
    1562 |
    1563 |
    1564 |     ER_dbg_va(FAC_UD, ASP_UD_SQL, "%s [%s]", UD_TAG, query->str);
    1565 |     sql_err = SQ_execute_query(tr->sql_connection, query->str, (SQ_result_set_t **)NULL);
    1566 |
    1567 |     /* Check for affected rows. One row should be affected */
    1568 |     num = SQ_get_affected_rows(tr->sql_connection);
    1569 |     if (num < 1) {
    1570 |          tr->error|=ERROR_U_DBS;
    1571 |          tr->succeeded=0;
    1572 |          if(sql_err) {
    1573 |           g_string_sprintfa(tr->error_script,"E[%d][:]:UPDATE last failed:%s\n" ,ERROR_U_DBS,SQ_error(tr->sql_connection));
    1574 | 	  ER_perror(FAC_UD, UD_SQL, "%s[%s]\n", SQ_error(tr->sql_connection), query->str);
    1575 | 	  die;
    1576 |          }
    1577 |          else {
    1578 | 	  ER_perror(FAC_UD, UD_SQL, "0 rows affected [%s]\n", query->str);
    1579 | 	  /* This is to check that this is really could happen */
    1580 | 	  die;
    1581 |          }
    1582 | 	 g_string_free(query, TRUE);
    1583 |          return(tr->succeeded);
    1584 |     }
    1585 |  g_string_free(query, TRUE);
    1586 |  return(tr->succeeded);
    1587 | } /* perform_update() */
    1588 |
    1589 |
    1590 |
    1591 |
    1592 | /************************************************************
    1593 | * int object_process(Transaction_t *tr)                     *
    1594 | *                                                           *
    1595 | * This is the interface between core and upper layer        *
    1596 | * All it gets is Transaction *tr, which contains all        *
    1597 | * necessary information, including the object in its        *
    1598 | * internal representation.                                  *
    1599 | *                                                           *
    1600 | * Returns: tr->succeeded: >0 success, 0 - error             *
    1601 | * Error code is stored in tr->error.                        *
    1602 | *                                                           *
    1603 | *************************************************************/
    1604 | int object_process(Transaction_t *tr)
    1605 | {
    1606 | int res;
    1607 | char *nic;
    1608 | int commit_now;
    1609 |
    1610 |    /* for fast loader we do not perform commits/rollbacks */
    1611 |    if(tr->load_pass == 0) commit_now = 0; else commit_now = 1;
    1612 |
    1613 |    /* create and initialize TR record for crash recovery */
    1614 |    TR_create_record(tr);
    1615 |
    1616 |    if(ACT_DELETE(tr->action)){
    1617 | 	 	ER_dbg_va(FAC_UD, ASP_UD_UPDLOG, "%s object: delete", UD_TAG);
    1618 | 		/* check referential integrity of deletion */
    1619 | 		UD_check_ref(tr);
    1620 | 	        /* for person & role - free the nic-handle in the NHR */
    1621 |                 if(ACT_UPD_NHR(tr->action) && tr->succeeded && ((tr->class_type==C_PN) || (tr->class_type==C_RO)) && tr->nh ){
    1622 |       	         res = NH_free(tr->nh, tr->sql_connection, commit_now);
    1623 |
    1624 | 		 if(res == -1) {
    1625 | 		   tr->succeeded=0;
    1626 | 		   tr->error |= ERROR_U_DBS;
    1627 | 		   ER_perror(FAC_UD, UD_SQL, "cannot delete nic handle");
    1628 | 		   die;
    1629 | 	         }
    1630 | 		 else if(res == 0) {
    1631 | 		   tr->succeeded=0;
    1632 | 		   tr->error |= ERROR_U_OBJ;
    1633 | 		   ER_perror(FAC_UD, UD_SQL, "nic handle not found");
    1634 | 		   die;
    1635 | 	         }
    1636 | 	        }
    1637 | 		/* if everything is Ok we are ready to commit */
    1638 | 		if (tr->succeeded){
    1639 | 		 /* update object_id and sequence_id fields */
    1640 |                  tr->sequence_id = get_sequence_id(tr);
    1641 | 		 TR_update_id(tr);
    1642 |
    1643 | 		 /* checkpoint the TR  - we are going to commit*/
    1644 | 		 CP_COMMIT(tr->action); TR_update_escript(tr); TR_update_status(tr);
    1645 |
    1646 | 		 /* send an ack */
    1647 | 		 UD_ack(tr);
    1648 |
    1649 | 		 /* delete the object and checkpoint it*/
    1650 | 	 	 UD_delete(tr);
    1651 | 		 UD_update_rx(tr, RX_OPER_DEL);
    1652 |
    1653 |                  /* we need to update sequence_id because it was changed during update */
    1654 | 		 CP_DELETE_PASSED(tr->action); TR_update_id(tr); TR_update_status(tr);
    1655 |
    1656 | 		 /* Commit nic-handle deletion to the repository */
    1657 |                  NH_commit(tr->sql_connection);
    1658 |
    1659 | 		 CP_COMMIT_NH_PASSED(tr->action); TR_update_status(tr);
    1660 |
    1661 | 		}
    1662 | 		else { /* just send an ack */
    1663 | 		 UD_ack(tr);
    1664 | 		}
    1665 | 		return(tr->succeeded); /*commit is not needed*/
    1666 |     }
    1667 |     else if(ACT_UPDATE(tr->action)){
    1668 | 	 	ER_dbg_va(FAC_UD, ASP_UD_UPDLOG, "%s object: update\n", UD_TAG);
    1669 | 	 	perform_update(tr);
    1670 |
    1671 | 	 	/* Commit nic-handle allocation (if any) to the repository if we are replacing dummy*/
    1672 |                 if(ACT_UPD_NHR(tr->action) && tr->succeeded && ((tr->class_type==C_PN) || (tr->class_type==C_RO)) && tr->nh ){
    1673 |                  /* convert nh to DB nIC handle before registration */
    1674 |                  /* because there nh will bee freed */
    1675 |                  nic = NH_convert(tr->nh);
    1676 |
    1677 | 		 if(nic==NULL)res=-1; else res = NH_register(tr->nh, tr->sql_connection, commit_now);
    1678 |
    1679 | 		 if(res == -1) {
    1680 | 		  tr->succeeded=0;
    1681 | 		  tr->error |= ERROR_U_DBS;
    1682 | 		  ER_perror(FAC_UD, UD_SQL, "cannot allocate nic handle\n");
    1683 | 		  die;
    1684 | 	         }
    1685 | 		 else if(res == 0) {
    1686 | 		  tr->succeeded=0;
    1687 | 		  tr->error |= ERROR_U_OBJ;
    1688 | 		  ER_perror(FAC_UD, UD_SQL, "nic handle already in use\n");
    1689 | 		  die;
    1690 | 	         }
    1691 | 	         else { /* copy the NH to the report to return to DBupdate */
    1692 | 	         /* Convert nh to the database format */
    1693 | 	          g_string_sprintfa(tr->error_script,"I[%d][%s]\n", A_NH, nic);
    1694 | 		  UT_free(nic);
    1695 | 	         }
    1696 |                 }
    1697 |     }
    1698 |     else if(ACT_CREATE(tr->action)){
    1699 | 	 	ER_dbg_va(FAC_UD, ASP_UD_OBJ, "%s object: create", UD_TAG);
    1700 | 	 	perform_create(tr);
    1701 |
    1702 | 		/* Commit nic-handle allocation (if any) to the repository */
    1703 |                 if(ACT_UPD_NHR(tr->action) && tr->succeeded && ((tr->class_type==C_PN) || (tr->class_type==C_RO)) && tr->nh ){
    1704 |                  /* convert nh to DB nIC handle before registration */
    1705 |       	         nic = NH_convert(tr->nh);
    1706 |
    1707 | 		 if(nic==NULL)res=-1; else res = NH_register(tr->nh, tr->sql_connection, commit_now);
    1708 |
    1709 | 		 if(res == -1) {
    1710 | 		  tr->succeeded=0;
    1711 | 		  tr->error |= ERROR_U_DBS;
    1712 | 		  ER_perror(FAC_UD, UD_SQL, "cannot allocate nic handle");
    1713 | 		  die;
    1714 | 	         }
    1715 | 		 else if(res == 0) {
    1716 | 		  tr->succeeded=0;
    1717 | 		  tr->error |= ERROR_U_OBJ;
    1718 | 		  ER_inf_va(FAC_UD, ASP_UD_UPDLOG, "[%ld] object: nic handle %s already in use", tr->transaction_id, nic);
    1719 | 		  g_string_sprintfa(tr->error_script,"E[%d][nic handle %s already in use]\n", A_NH, nic);
    1720 | 	         }
    1721 | 	         else { /* copy the NH to the report to return to DBupdate */
    1722 | 	          g_string_sprintfa(tr->error_script,"I[%d][%s]\n", A_NH, nic);
    1723 | 		  UT_free(nic);
    1724 | 	         }
    1725 |                 }
    1726 |
    1727 |      }
    1728 |      else {
    1729 | 	 	ER_inf_va(FAC_UD, ASP_UD_UPDLOG, "[%ld] object: unknown action", tr->transaction_id);
    1730 | 	 	tr->succeeded=0;
    1731 | 	 	tr->error|=ERROR_U_BADOP;
    1732 | 	 	return(tr->succeeded);
    1733 |      }
    1734 |
    1735 |    if(tr->load_pass == 0) { /* not for fast loader*/
    1736 |       /* update object_id and sequence_id fields */
    1737 |       TR_update_id(tr);
    1738 |
    1739 |       if (tr->succeeded) {
    1740 | /*ER_dbg_va(FAC_UD, ASP_UD_OBJ, "%s Commit transaction\n", UD_TAG);      */
    1741 |         /* checkpoint the TR  - we are going to commit*/
    1742 | 	CP_COMMIT(tr->action); TR_update_escript(tr); TR_update_status(tr);
    1743 |
    1744 | 	/* send an ack */
    1745 |         UD_ack(tr);
    1746 |         /* commit the transaction and checkpoint it */
    1747 |
    1748 |         UD_commit(tr);
    1749 | 	/* Commit nic-handle modifications to the repository */
    1750 |
    1751 |         NH_commit(tr->sql_connection);
    1752 |
    1753 | 	CP_COMMIT_NH_PASSED(tr->action); TR_update_status(tr);
    1754 | 	/* TR will be marked as clean in UD_create_serial() */
    1755 |       }
    1756 |       else {
    1757 | /*ER_dbg_va(FAC_UD, ASP_UD_OBJ, "%s roll back transaction\n", UD_TAG);      */
    1758 |         /* send an ack */
    1759 |         UD_ack(tr);
    1760 |         UD_rollback(tr);
    1761 |
    1762 | 	CP_ROLLBACK_PASSED(tr->action); TR_update_status(tr);
    1763 |
    1764 | 	/* rollback nic-handle modifications to the repository */
    1765 |         NH_rollback(tr->sql_connection);
    1766 |
    1767 |
    1768 | 	CP_ROLLBACK_NH_PASSED(tr->action); TR_update_status(tr);
    1769 | 	/* Delete TR record if in update mode. Next time (if any) DBupdate tries to submit, we'll start from scratch */
    1770 | 	/* In NRTM mode we create serial anyway, so the record will be deleted  */
    1771 | 	/* after serial is created TR record will be deleted in */
    1772 |
    1773 |       }
    1774 |     }
    1775 |  return(tr->succeeded);
    1776 | } /* object_process() */
    1777 |