## modules/ud/ud_core.c

/* [<][>][^][v][top][bottom][index][help] */

## FUNCTIONS

This source file includes following functions.

1. convert_if
2. convert_rf
3. convert_as
4. convert_as_range
5. convert_time
6. get_set_name
7. get_object_id
8. get_minmax_id
9. get_qresult_str
10. get_field_str
11. get_sequence_id
12. get_ref_id
13. isdummy
14. isnichandle
15. process_reverse_domain
16. insert_reverse_domain
17. update_reverse_domain
18. auth_member_of
19. create_dummy
20. update_attr
21. each_attribute_process
22. ud_each_primary_key_select
23. perform_create
24. perform_update
25. object_process

       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)
         /* [<][>][^][v][top][bottom][index][help] */
      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)
         /* [<][>][^][v][top][bottom][index][help] */
      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)
         /* [<][>][^][v][top][bottom][index][help] */
     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)
         /* [<][>][^][v][top][bottom][index][help] */
     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)
         /* [<][>][^][v][top][bottom][index][help] */
     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)
         /* [<][>][^][v][top][bottom][index][help] */
     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)
         /* [<][>][^][v][top][bottom][index][help] */
     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)
         /* [<][>][^][v][top][bottom][index][help] */
     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)
         /* [<][>][^][v][top][bottom][index][help] */
     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,
         /* [<][>][^][v][top][bottom][index][help] */
     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)
         /* [<][>][^][v][top][bottom][index][help] */
     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)
         /* [<][>][^][v][top][bottom][index][help] */
     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)
         /* [<][>][^][v][top][bottom][index][help] */
     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)
         /* [<][>][^][v][top][bottom][index][help] */
     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,
         /* [<][>][^][v][top][bottom][index][help] */
     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)
         /* [<][>][^][v][top][bottom][index][help] */
     575 #define update_reverse_domain(tr, pr) process_reverse_domain(tr, pr, 1)
         /* [<][>][^][v][top][bottom][index][help] */
     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)
         /* [<][>][^][v][top][bottom][index][help] */
     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)
         /* [<][>][^][v][top][bottom][index][help] */
     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)
         /* [<][>][^][v][top][bottom][index][help] */
     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)
         /* [<][>][^][v][top][bottom][index][help] */
    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)
         /* [<][>][^][v][top][bottom][index][help] */
    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)
         /* [<][>][^][v][top][bottom][index][help] */
    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)
         /* [<][>][^][v][top][bottom][index][help] */
    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)
         /* [<][>][^][v][top][bottom][index][help] */
    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

/* [<][>][^][v][top][bottom][index][help] */