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