## modules/ud/ud_core.c

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

## DEFINITIONS

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_qresult_str
9. get_field_str
10. get_sequence_id
11. get_ref_id
12. isdummy
13. process_reverse_domain
14. auth_member_of
15. create_dummy
16. update_attr
17. create_attr
18. each_attribute_process
19. ud_each_primary_key_select
20. perform_create
21. perform_update
22. object_process

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

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