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