1    | /***************************************
2    |   $Revision: 1.5 $
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   | #include "UD_queries.def" 
36   | 
37   | char * const Type2main[] = {
38   | "as_block",
39   | "as_set",
40   | "aut_num",
41   | "domain",
42   | "inet_rtr",
43   | "inet6num",
44   | "inetnum",
45   | "key_cert",
46   | "limerick",
47   | "mntner",
48   | "person_role", //pn
49   | "person_role", //ro
50   | "route",
51   | "route_set",
52   | NULL
53   | }; /* Main tables names for object types */
54   | 
55   | 
56   | static int perform_update(Transaction_t *tr);
57   | 
58   | static int perform_create(Transaction_t *tr);
59   | 
60   | static void each_primary_key_select(void *element_data, void *result_ptr);
61   | 
62   | static void each_attribute_process(void *element_data, void *tr_ptr);
63   | 
64   | static int update_attr(Attribute_t *attr, Transaction_t *tr);
65   | 
66   | static int create_dummy(Attribute_t *attr, Transaction_t *tr);
67   | 
68   | static int auth_member_of(Attribute_t *attr, Transaction_t *tr);
69   | 
70   | 
71   | 
72   | 
73   | 
74   | /***************************************************
75   | * char *s_split(char *line)                        *
76   | *                                                  *
77   | * Consequently returns words of the 'line'         * 
78   | * When there are no words it returns NULL          *
79   | * You need to retreive all words !                 *
80   | *                                                  *
81   | * NB This function damages 'line' replacing        *
82   | * whitespace with '\0'                             *
83   | * *************************************************/
84   | static char *s_split(char *line)
85   | {
86   | static char *delim;
87   | static char *token=NULL;
88   | 
89   |  if(token==NULL)token=line;
90   |  else token=delim;
91   |  
92   |  if(token==NULL)return(token);
93   |  while(isspace((int)*token))token++;
94   |  delim=token;
95   |  
96   |  while(!isspace((int)*delim)) {
97   |  	if((*delim)=='\0'){
98   |  		if(delim==token)token=NULL;
99   |  		delim=NULL; return(token);
100  |  	}
101  |  	delim++;
102  |  }
103  |  *delim='\0'; delim++;
104  |  return(token);
105  | 
106  | }
107  | 
108  | /* The same as s_split() but returns nwords words */
109  | /*  and the rest of the line                      */
110  | static char *s_splitn(char *line, int nwords)
111  | {
112  | static char *delim;
113  | static char *token=NULL;
114  | static int w=0;
115  | 
116  |  
117  |  if(token==NULL)token=line;
118  |  else token=delim;
119  |  
120  |  w++; if(w>nwords){ w=0; delim=token; token=NULL; return(delim); }
121  |  
122  |  if(token==NULL)return(token);
123  |  while(isspace((int)*token))token++;
124  |  delim=token;
125  |  
126  |  while(!isspace((int)*delim)) {
127  |  	if((*delim)=='\0'){
128  |  		if(delim==token)token=NULL;
129  |  		delim=NULL; return(token);
130  |  	}
131  |  	delim++;
132  |  }
133  |  *delim='\0'; delim++;
134  |  return(token);
135  | 
136  | 
137  | }
138  | 
139  | /**********************************************************
140  | * Attribute expansion/conversion functions                *
141  | ***********************************************************/
142  | 
143  | /* Convert route attribute into numbers */
144  | er_ret_t expand_rt(char *avalue, unsigned int *prefix, unsigned int *prefix_length)
145  | {
146  | ip_prefix_t pref;
147  | er_ret_t ret;
148  | 
149  |  ret = IP_pref_e2b(&pref, avalue);
150  |  *prefix = pref.ip.words[0];
151  |  *prefix_length=pref.bits;
152  |  return(ret);
153  | }
154  | 
155  | /* Convert ifaddr attribute into numbers */
156  | er_ret_t convert_if(char *avalue, unsigned int *address)
157  | {
158  | char *delim;
159  | ip_addr_t ipaddr;
160  | er_ret_t ret;
161  | 
162  |   if ((delim=index(avalue, ' '))!=NULL) *delim='\0';
163  |   ret = IP_addr_e2b(&ipaddr, avalue);
164  |   *address = ipaddr.words[0];
165  |   return(ret);
166  | }
167  | 
168  | /* Convert inetnum attribute into numbers */
169  | er_ret_t convert_in(char *rangstr, unsigned int *begin_in, unsigned int *end_in)
170  | {
171  | ip_range_t myrang;
172  | er_ret_t ret;
173  | 
174  |   if( IP_rang_e2b(&myrang, rangstr) != IP_OK ) {
175  | // see if's a valid IP, maybe it's an IPv4 classful range
176  |    if( IP_addr_e2b( &myrang.begin, rangstr ) == IP_OK )
177  |      if ((ret=IP_rang_classful( &myrang , &myrang.begin )) != IP_OK ) return (ret);
178  |   }
179  |   *begin_in=myrang.begin.words[0];
180  |   *end_in=myrang.end.words[0];
181  |   return(IP_OK);
182  | }
183  | 
184  | /* Convert refer attribute. Free host after use ! */
185  | char *convert_rf(char *avalue, int *type, int *port)
186  | {
187  | char *delim, *token;
188  | char buff[STR_M];
189  | char *host;
190  | 
191  |   host=NULL;
192  |   strcpy(buff, avalue);
193  |   g_strchug(buff);
194  |   delim=index(buff, ' ');
195  |   *delim='\0';
196  |   delim++; 
197  | 
198  | // convert the type      
199  |   if(strcmp(buff, S_RIPE)==0)*type=RF_RIPE;
200  |    else if(strcmp(buff, S_INTERNIC)==0)*type=RF_INTERNIC;
201  |     else if(strcmp(buff, S_SIMPLE)==0)*type=RF_SIMPLE;
202  | 
203  |   token=delim;
204  |   g_strchug(token);
205  |   delim=index(token, ' ');
206  |   if(delim){
207  |    *delim='\0';
208  |    delim++; 
209  |   }	      
210  | // convert the hostname      
211  |   host = g_strdup(token);
212  |       
213  | // convert port number      
214  |   if(delim){
215  |     token=delim;	
216  |     *port = atoi(token);
217  |     if (*port==0) *port=RF_DEF_PORT; // default port number
218  |   } else *port=RF_DEF_PORT;
219  |   return(host);
220  | }
221  | 
222  | 
223  | /* Convert AS# into integer */
224  | static int convert_as(char *as)
225  | {
226  | char *ptr;
227  |  ptr=as; ptr++; ptr++; 
228  |  return(atoi(ptr));   
229  | }
230  | 
231  | /* Convert AS range (AS4321 - AS5672) into numbers */
232  | int convert_as_range(const char *as_range, int *begin, int *end)
233  | {
234  | char buf[STR_M];
235  |   strcpy(buf, as_range); //save it
236  |   *begin=convert_as(s_split(buf));
237  |   s_split(buf); // should be '-'
238  |   *end=convert_as(s_split(buf));
239  |   while(s_split(buf));
240  |   return(0);
241  | }
242  | 
243  | /* Convert time in ASCII format (19991224) into time_t unix time */
244  | time_t convert_time(char *asc_time)
245  | {
246  | struct tm tm;
247  | char buf[STR_S];
248  | char *ptr;
249  | 
250  |   
251  |   bzero(&tm, sizeof(tm));
252  |   
253  |   strncpy(buf, asc_time, 4); ptr=buf+4; *ptr='\0';
254  |   tm.tm_year = atoi(buf) - 1900;
255  |   
256  |   strncpy(buf, (asc_time+4), 2); ptr=buf+2; *ptr='\0';
257  |   tm.tm_mon = atoi(buf) - 1;
258  |   
259  |   strncpy(buf, (asc_time+6), 2); ptr=buf+2; *ptr='\0';
260  |   tm.tm_mday = atoi(buf);
261  |   
262  |   return(mktime(&tm));
263  | 
264  | }     
265  | 
266  | /*********************************
267  | * M I S C ***********************/
268  | 
269  | /************************************************************
270  | * long get_object_id()                                      *
271  | * Queries the database for an object.                       *
272  | * For constructing a query uses each__primary_key_select()  *
273  | *                                                           *
274  | * Returns:                                                  *
275  | * >0 - object exists, returns object_id                     *
276  | * 0  - object does not exist                                *
277  | * -1 - DB error (f.e. more than one object with the same PK)     *
278  | *                                                           *
279  | * **********************************************************/
280  | long get_object_id(Transaction_t *tr)
281  | {
282  | Object_t *obj=tr->object;
283  | SQ_result_set_t *sql_result;
284  | SQ_row_t *sql_row;
285  | char *sql_str;
286  | GString *query;
287  | long object_id=0;
288  | 
289  |  if ((query = g_string_sized_new(STR_XL)) == NULL){ 
290  |   fprintf(stderr, "E: cannot allocate gstring\n"); 
291  |   tr->succeeded=0;
292  |   tr->error |= ERROR_U_MEM;
293  |   return(ERROR_U_MEM); 
294  |  }
295  |  
296  |  g_string_sprintf(query, "SELECT * FROM %s WHERE",Type2main[obj->type]);
297  |  g_slist_foreach(obj->attributes, each_primary_key_select, query);
298  | /* truncate the last ' AND '*/
299  |  g_string_truncate(query, (query->len) - 4); 
300  |         
301  | /* execute query */
302  |  sql_result=SQ_execute_query(SQ_STORE, tr->sql_connection, query->str);
303  |  g_string_free(query, TRUE);
304  |  
305  |  if(sql_result == NULL) {
306  |    fprintf(stderr,"ERROR: %s\n", SQ_error(tr->sql_connection));
307  |    return(-1);
308  |  }
309  | 
310  |  if ((sql_row = SQ_row_next(sql_result)) != NULL) {
311  | /* Object exists */
312  |    sql_str = SQ_get_column_string(sql_result, sql_row, OBJECT_ID);
313  |    if (sql_str != NULL) {
314  |      object_id = atol(sql_str);
315  |      free(sql_str);
316  |    }
317  | 
318  | /* We must process all the rows of the result */
319  | /* otherwise we'll have them as part of the next qry */      
320  |    while ( (sql_row = SQ_row_next(sql_result)) != NULL) object_id=-1;
321  |  } else 
322  |       object_id=0;  // object does not exist
323  |    
324  |  if(sql_result)SQ_free_result(sql_result);
325  |  return(object_id);
326  | }
327  | 
328  | /************************************************************
329  | * get_field_str()                                           *
330  | *                                                           *
331  | * Returns string containing the field.                      *
332  | *  field - field name to be retrieved                       *
333  | *  ref_tbl_name - name of the table containing the field    *
334  | *  ref_name - reference name                                *
335  | *  attr_value - reference value                             *
336  | *  condition - additional condition ( f.e. 'AND dummy=0'    *
337  | *                                                           *
338  | * Returns:                                                  *
339  | *  String containing the field. Needs to be freed after use *
340  | *  NULL in case of an error                                 *
341  | *                                                           *
342  | *************************************************************/
343  | char *get_field_str(Transaction_t *tr, char *field, 
344  | 			   char *ref_tbl_name, char *ref_name, 
345  | 			   char * attr_value, char *condition)
346  | {
347  | static char query[STR_L];
348  | SQ_result_set_t *sql_result;
349  | SQ_row_t *sql_row;
350  | char *sql_str;
351  | 
352  |  sprintf(query, "SELECT %s FROM %s "
353  |                 "WHERE %s='%s' ",
354  | 		field, ref_tbl_name, ref_name, attr_value);
355  |  if (condition)strcat(query, condition);
356  | 
357  | //fprintf(stderr, "D:<get_field_str>:query: %s\n", query);
358  |  sql_result=SQ_execute_query(SQ_STORE, tr->sql_connection, query);
359  |  
360  |  if(sql_result == NULL) {
361  |     fprintf(stderr,"ERROR: %s\n", SQ_error(tr->sql_connection));
362  |     return(NULL);
363  |  }
364  |         
365  | 	 
366  |  if ((sql_row = SQ_row_next(sql_result)) != NULL) {
367  | 	sql_str = SQ_get_column_string(sql_result, sql_row, 0);
368  | 
369  |      /* We must process all the rows of the result,*/
370  |      /* otherwise we'll have them as part of the next qry */
371  | 	while ( (sql_row = SQ_row_next(sql_result)) != NULL) {
372  | 	  fprintf(stderr, "E:<get_field_str> error : Dupl PK[%s]\n", query);
373  | 	  if(sql_str)free(sql_str); sql_str=NULL;
374  | 	}
375  |  }
376  |  else sql_str=NULL;
377  |  
378  |  if(sql_result){ SQ_free_result(sql_result); sql_result=NULL; }
379  |  return(sql_str);
380  | }
381  | 
382  | /************************************************************
383  | * long get_sequence_id(Transaction_t *tr)
384  | * >0 - success
385  | * -1 - sql error
386  | *
387  | * **********************************************************/
388  | 
389  | long get_sequence_id(Transaction_t *tr)
390  | {
391  | char *sql_str;
392  | char str_id[STR_M];
393  | long sequence_id=-1;
394  | 
395  | 
396  |   sprintf(str_id, "%ld", tr->object_id);
397  |   sql_str= get_field_str(tr, "sequence_id", "last", "object_id", str_id, NULL);
398  |   if(sql_str) {
399  |        	  sequence_id = atol(sql_str);
400  | //       	  fprintf(stderr, "D: Retrieved set serial id = %ld\n", sequence_id);
401  |        	  free(sql_str);
402  |   }
403  |   
404  |   return(sequence_id);
405  | 
406  | }
407  | 
408  | 
409  | /************************************************************
410  | * long get_ref_id(char *ref_tbl_name, char *ref_name, char * attr_value)
411  | * >0 - success
412  | * -1 - sql error
413  | *
414  | * **********************************************************/
415  | 
416  | static long get_ref_id(Transaction_t *tr, char *ref_tbl_name, char *ref_name, char * attr_value, char *condition)
417  | {
418  | char *sql_str;
419  | long ref_id=-1;
420  | 
421  | //fprintf(stderr, "D:<get_ref_id>: entering...\n");
422  | 
423  | 	sql_str= get_field_str(tr, "object_id", ref_tbl_name, ref_name, attr_value, condition);
424  | 	if(sql_str) {
425  | 		 ref_id = atol(sql_str);
426  | //		 fprintf(stderr, "D: Retrieved set serial id = %ld\n", ref_id);
427  | 		 free(sql_str);
428  | 	}
429  | 	return(ref_id);	
430  | }
431  | 
432  | 
433  | static int isnichandle(char *name)
434  | {
435  |  return(MA_isset(WK_new(name), WK_NIC_HDL));
436  | }
437  | 
438  | static int sql_info(SQ_connection_t *sql_connection, int info[3])
439  | {
440  | int ii;
441  | char *colon, *buf_ptr, buf[20]; 
442  | char *infoline;
443  | 
444  | //fprintf(stderr, "D: Getting additional information about query\n");
445  |   infoline=mysql_info(sql_connection); 
446  | //fprintf(stderr, "D: %s\n", infoline);  
447  |   ii=0;
448  |   colon = infoline;
449  |   while (*colon != '\0') {
450  |    colon++;
451  |    buf_ptr=buf;
452  |    if(isdigit((int)*colon)){
453  |     while(isdigit((int)*colon)){
454  |      *buf_ptr=*colon; buf_ptr++; colon++;
455  |     }
456  |     *buf_ptr='\0';
457  |     info[ii]=atoi(buf); ii++;
458  |    } 
459  |   }
460  | //  free(infoline);
461  | //fprintf(stderr, "D: return %d\n", res[res_type]);  
462  | return(0);
463  | }
464  | 
465  | 
466  | static char *get_set_name(C_Type_t class_type)
467  | {
468  |  switch(class_type){
469  |  case C_RT: 	return("route_set");
470  |  case C_AN: 	return("as_set");
471  |  default:	return(NULL);
472  |  }
473  | }
474  | 
475  | 
476  | /************************************************************
477  | * auth_member_of()                                          *
478  | *                                                           *
479  | * Function that checks the authorization for membership     *
480  | * (i.e. if the object is authorized to be a memeber by      *
481  | * mbrs-by-ref attribute of the set is refers by member-of   *
482  | * attribute).                                               *
483  | * First checks if 'mbrs-by-ref: ANY'                        *
484  | * If not then checks that maintner referenced by            *
485  | * mbrs-by-ref attribute of the set is the one in mnt-by.    *
486  | *                                                           *
487  | * Returns:                                                  *
488  | * 0  success                                                *
489  | * 1  not allowed                                            *
490  | * -1 SQL error                                              *  
491  | *                                                           *
492  | *************************************************************/
493  | static int auth_member_of(Attribute_t *attr, Transaction_t *tr)
494  | {
495  | GString *query;
496  | SQ_result_set_t *sql_result;
497  | SQ_row_t *sql_row;
498  | //char *sql_str;
499  | char *set_name;
500  | //long set_id;
501  | //my_ulonglong num;
502  | int error;
503  | 
504  | 
505  |  error=0;
506  | 	
507  | /* Check if set has mbrs_by_ref==ANY 
508  |    In such case mbrs_by_ref.mnt_id==0 
509  | */
510  | 
511  |  if ((query = g_string_sized_new(STR_XL)) == NULL){
512  |   tr->succeeded=0;
513  |   tr->error |= ERROR_U_MEM; 
514  |   fprintf(stderr, "E: cannot allocate gstring\n"); 
515  |   return(-1); 
516  |  }
517  |  
518  |  set_name= get_set_name(tr->class_type);
519  | // fprintf(stderr, "D:<auth_member_of>: Got set name: %s\n", set_name);	
520  |  g_string_sprintf(query,"SELECT %s.object_id FROM mbrs_by_ref, %s "
521  | 			"WHERE mbrs_by_ref.object_id=%s.object_id "
522  | 			"AND %s.%s='%s' AND mbrs_by_ref.mnt_id=0 ", 
523  | 			set_name, set_name, set_name, set_name, set_name, attr->value);
524  | // fprintf(stderr, "D:<auth_member_of>: query: %s\n", query->str);
525  | 
526  |  sql_result=SQ_execute_query(SQ_STORE, tr->sql_connection, query->str);
527  | // if (sql_result ==NULL) { // ????????
528  | //   fprintf(stderr, "E:<auth_member_of>: NULL SQL result[%s]\n", query->str);
529  | //   g_string_free(query, TRUE);
530  | //   return(1);
531  | // }	
532  | 
533  |  if ((sql_result==NULL) || ((sql_row = SQ_row_next(sql_result))==NULL)){
534  |     if(sql_result){ SQ_free_result(sql_result); sql_result=NULL; }
535  | 
536  | /* Check if our mnt_by belongs to mbrs_by_ref list of the set */
537  |     g_string_sprintf(query, "SELECT mbrs_by_ref.object_id FROM route_set, mbrs_by_ref, mnt_by "
538  |  			    "WHERE mbrs_by_ref.mnt_id=mnt_by.mnt_id "
539  |     			    "AND mnt_by.object_id=%ld "
540  |     			    "AND %s.object_id=mbrs_by_ref.object_id "
541  |     			    "AND %s.%s='%s' "
542  |     			    "AND mnt_by.thread_id!=0 ",
543  |     			    tr->object_id, set_name, set_name, set_name, attr->value);
544  | 
545  | //    	fprintf(stderr, "D:<auth_member_of>: query: %s\n", query->str);						
546  |     							
547  |     sql_result=SQ_execute_query(SQ_STORE, tr->sql_connection, query->str);
548  | 
549  |     if(sql_result == NULL) {
550  |        fprintf(stderr,"ERROR: %s\n", SQ_error(tr->sql_connection));
551  |        g_string_free(query, TRUE);
552  |        return(-1);
553  |     }
554  | 
555  |     if ((sql_row = SQ_row_next(sql_result)) == NULL) {
556  | /* Membership is not authorized */
557  |       fprintf(stderr, "E:<auth_member_of> : Membership is not autorized[%s]\n", query->str);
558  |       if(sql_result){ SQ_free_result(sql_result); sql_result=NULL; }
559  |       g_string_free(query, TRUE);
560  |       return(1);
561  |     }
562  |  }
563  | 	
564  | //	sql_str = SQ_get_column_string(sql_result, sql_row, 0);
565  | /* We must process all the rows of the result, otherwise we'll have them as part of the next qry */
566  |  while ( (sql_row = SQ_row_next(sql_result)) != NULL) {
567  |    fprintf(stderr, "E:<auth_member_of> error : More than one object with the same PK\n");
568  |    error=-1;
569  |  }
570  |  if(sql_result){ SQ_free_result(sql_result); sql_result=NULL; }
571  |  g_string_free(query, TRUE);
572  |  return(0);
573  | }/* auth_member_of()  */
574  | 	
575  | 
576  | /************************************************************
577  | * create_dummy()                                            *
578  | *                                                           *
579  | * Function that creates a dummy object (that is one that    *
580  | * is referenced from an object but does not                 *
581  | * exist in the database).                                   *
582  | * Dummy object exists only in relevant main and 'last'      *
583  | * tables. Its creation is controlled by tr->dummy_allowed.  *
584  | * Queries for the dummies are defined in Dummy[] array.     *
585  | *                                                           *
586  | * Returns:                                                  *
587  | * 0  success                                                *
588  | * 1  no rf integrity and dummy not allowed
589  | * -1 SQL error                                              *
590  | *                                                           *
591  | *************************************************************/
592  | static int create_dummy(Attribute_t *attr, Transaction_t *tr) 
593  | {
594  | SQ_result_set_t *sql_result;
595  | char *query_fmt;
596  | int num;
597  | long dummy_id;
598  | char query[STR_L];
599  | //int result;
600  | char *set_name;
601  | char *p_name;
602  | int query_type;
603  | long timestamp;
604  | char str_id[STR_M];
605  | gchar *chopped_nh=NULL;
606  | gchar *attr_value=NULL;
607  | 
608  | 
609  | 	query_fmt = Dummy[attr->type].qry;
610  | 	if (strcmp(query_fmt, "") == 0) { fprintf(stderr, "E:<create_dummy>: empty query string\n"); return(1); }
611  | 	if ((attr->type!=A_MO) &&  (tr->dummy != 1)) return(1);  
612  | 
613  | 	/* insert dummy in the last table */
614  | 		sprintf(str_id, "%ld", tr->object_id);
615  | 		timestamp=time(NULL);
616  | 		sprintf(query, "INSERT INTO last SET thread_id=%d, timestamp=%ld, object_type=%d, object='DUMMY for %s'", 
617  | 								tr->thread_ins, timestamp, DUMMY_TYPE, str_id);
618  | // fprintf(stderr, "D: making dummy entry in the last table\n %s\n", query);
619  | 		sql_result=SQ_execute_query(SQ_STORE, tr->sql_connection, query);
620  | 		num = mysql_affected_rows(tr->sql_connection);
621  | //		fprintf(stderr, "D: query: %d rows affected\n", num);
622  | 		if (sql_result)SQ_free_result(sql_result);  
623  | 		if ((num == -1) || (num == 0)) {
624  | //fprintf(stderr, "E: dummy->last:[%s]\n", query);
625  | 			return(-1);
626  | 		}	
627  | 	
628  | 	/* insert dummy in the main table */
629  | 	dummy_id=mysql_insert_id(tr->sql_connection); 
630  | 	tr->dummy_id[tr->ndummy]=dummy_id;
631  | 	tr->ndummy++; // increase number of attempts to create dummy
632  | //	fprintf(stderr, "D:<create_dummy>:dummy_id=%ld\n", dummy_id);
633  | 	query_type=Dummy[attr->type].qtype;
634  | 	switch (query_type) {	
635  | 	 case UD_AX_PR:
636  | 			// chop nic-hdl if bigger that MAX_NIC_HDL
637  |     		 	if(strlen(attr->value)>MAX_NIC_HDL){
638  |     			 chopped_nh = g_strndup(attr->value, MAX_NIC_HDL);
639  |     			 attr_value=chopped_nh;
640  |     		 	} else attr_value = attr->value;
641  |     		 	sprintf(query, query_fmt, tr->thread_ins, dummy_id, attr_value, DUMMY_TYPE);
642  |    		 	if(chopped_nh){ free(chopped_nh); chopped_nh=NULL;}
643  | 			break;
644  | 	 case UD_AX_MT:	
645  | 	 		sprintf(query, query_fmt, tr->thread_ins, dummy_id, attr->value, DUMMY_TYPE);
646  | 			break;
647  | 		// as-set, route-set
648  | 	 case UD_AX_MO:	
649  | 	 		set_name = get_set_name(tr->class_type);
650  | 			sprintf(query, query_fmt, set_name, tr->thread_ins, dummy_id, set_name, attr->value);	  
651  | 			break;
652  | 	 default:
653  | 		        fprintf(stderr, "E: query not defined for this type of attribute[%d]\n", attr->type);
654  |                         break;
655  | 	}
656  | 	
657  | //fprintf(stderr, "D: query: %s\n", query);
658  | 	sql_result=SQ_execute_query(SQ_STORE, tr->sql_connection, query);
659  | 	num = mysql_affected_rows(tr->sql_connection);
660  | //	fprintf(stderr, "D: query: %d rows affected\n", num);
661  | 	if (sql_result)SQ_free_result(sql_result);
662  | 	if ((num == -1) || (num == 0)) {
663  | fprintf(stderr, "E: dummy->main:[num=%d][%s]\n", num, query);
664  | 		return(-1);
665  | 	}
666  | 	
667  | 	if( query_type == UD_AX_MO ){ // Create row in mbrs_by_ref
668  | 		sprintf(query, " INSERT mbrs_by_ref SET thread_id=%d, object_id=%ld, mnt_id=0, object_type=%d ", 
669  | 					tr->thread_ins,dummy_id, DUMMY_TYPE);
670  | //		fprintf(stderr, "D: query: %s\n", query);
671  | 		sql_result=SQ_execute_query(SQ_STORE, tr->sql_connection, query);
672  |  		num = mysql_affected_rows(tr->sql_connection);
673  | //		fprintf(stderr, "D: query: %d rows affected\n", num);
674  | 		if (sql_result)SQ_free_result(sql_result);
675  | 	  	if ((num == -1) || (num == 0)) {
676  | 			fprintf(stderr, "E: dummy->main:[num=%d][%s]\n", num, query);
677  | 			return(-1);
678  | 	  	}
679  | 	}
680  | 	else
681  | 	if( (query_type == UD_AX_PR) && (!isnichandle (attr->value)) ){ // Create rows in names
682  | 	  // parse the names
683  | //	  fprintf(stderr,"adding names for dummy\n");
684  | 	   query_fmt = Insert[A_PN].qry;
685  | 	   attr_value = g_strdup(attr->value);
686  | 	   while((p_name=s_split(attr_value))){
687  | 		sprintf(query, query_fmt, tr->thread_ins, dummy_id, DUMMY_TYPE, p_name);
688  | //		fprintf(stderr, "D: query: %s\n", query);
689  | 		sql_result=SQ_execute_query(SQ_STORE, tr->sql_connection, query);
690  |  		num = mysql_affected_rows(tr->sql_connection);
691  | //		fprintf(stderr, "D: query: %d rows affected\n", num);
692  | 		if (sql_result)SQ_free_result(sql_result);
693  | 	   }
694  | 	   free(attr_value);
695  | 	}
696  | 	
697  | 	return(0);
698  | }
699  | 
700  | /************************************************************
701  | * update_attr()                                             *
702  | *                                                           *
703  | * Function that updates an attribute if it already exists.  *
704  | * Called from each_attribute_proces() function if it        *
705  | * cannot insert the row.                                    *
706  | * Queries for the attributes are defined in Update[] array. *
707  | *                                                           *
708  | * Returns: Nothing. Error code is stored in tr->succeeded.  *
709  | *                                                           *
710  | *************************************************************/
711  | static int update_attr(Attribute_t *attr, Transaction_t *tr)
712  | {
713  | SQ_result_set_t * sql_result;
714  | int num;
715  | char *query_fmt;
716  | //GString *query;
717  | char *set_name;
718  | unsigned int if_address;
719  | char * rf_host;
720  | int rf_port, rf_type;
721  | gchar *chopped_nh=NULL;
722  | char *a_value;
723  | //int dupl;
724  | int sq_info[3];
725  | char * condition;
726  | char query[STR_L];
727  | 
728  |  if(tr->load_pass!=0) return(0);
729  | 
730  | //	fprintf(stderr, "D: updating attribute...\n");
731  |    
732  |    query_fmt = Update[attr->type].qry;
733  |    if (strcmp(query_fmt, "") == 0) return(0);
734  | 
735  |    switch (Update[attr->type].qtype) {
736  |          case UD_MAIN_: sprintf(query, query_fmt, tr->thread_upd, tr->object_id);
737  |                         break;
738  | 	 case UD_MA_PR: 
739  | 	 		sprintf(query, query_fmt, tr->thread_upd, tr->class_type, tr->object_id);
740  | 			break;	
741  | 	 case UD_MA_LA: // save the new value for commit
742  | 			//g_string_free(query, TRUE);
743  | 			tr->save=attr->value;
744  | 			return(0);
745  | 			break;			
746  | 	 case UD_AX_PR:
747  | 	 		a_value = attr->value;
748  | 	 		if(strlen(attr->value)>MAX_NIC_HDL){ // This is for non-conformant admin-c, etc.
749  | 	 		 chopped_nh = g_strndup(attr->value, MAX_NIC_HDL);
750  | 	 		 a_value=chopped_nh;
751  | 	 		}
752  | 	 		if (tr->dummy!=1)condition="AND dummy=0 "; else condition=NULL;
753  | 	 		sprintf(query, query_fmt, tr->thread_upd, tr->object_id, 
754  | 	 			get_ref_id(tr, "person_role", "nic_hdl", a_value, condition));
755  | 	 		if(chopped_nh) free(chopped_nh);
756  | 	 		break;
757  | 	 case UD_AX_MT: 
758  | 	 		if (tr->dummy!=1)condition="AND dummy=0 "; else condition=NULL;
759  | 	 		sprintf(query, query_fmt, tr->thread_upd, tr->object_id, 
760  | 	 			get_ref_id(tr, "mntner", "mntner", attr->value, condition));
761  | 	 		break;
762  | 	 case UD_AX_MO: 
763  | 	 		set_name = get_set_name(tr->class_type);
764  | //	    	      fprintf(stderr, "D: retrieved set name: %s\n", set_name);
765  | 			if (tr->dummy!=1)condition="AND dummy=0 "; else condition=NULL;
766  | 			sprintf(query, query_fmt, tr->thread_upd, tr->object_id, 
767  | 					get_ref_id(tr, set_name, set_name, attr->value, condition));
768  | 			break;	    			
769  |     	 case UD_AX_MR:
770  |       			if ((strcmp(attr->value, "ANY")==0) || (strcmp(attr->value, "any")==0) || (strcmp(attr->value, "Any")==0))
771  |       		 	sprintf(query, query_fmt, tr->thread_upd, tr->object_id, 
772  |       		 	 	get_ref_id(tr, "mntner", "mntner", "ANY",NULL));
773  |       			else {  
774  |       		 	 if (tr->dummy!=1)condition="AND dummy=0 "; else condition=NULL;
775  |       		 	 sprintf(query, query_fmt, tr->thread_upd, tr->object_id, 
776  |       		 	 	get_ref_id(tr, "mntner", "mntner", attr->value, condition));
777  |       		 	}
778  | 			break;
779  | 	 case UD_LEAF_: 
780  | 	 		sprintf(query, query_fmt, tr->thread_upd, tr->object_id, attr->value);
781  | 			break;
782  | 	 case UD_LF_IF:
783  | 		// Convert ascii ip -> numeric one. Later to save in tr->save while processing INSERT
784  | 			convert_if(attr->value, &if_address);
785  | 			sprintf(query, query_fmt, tr->thread_upd, tr->object_id, if_address);
786  |     			break;
787  | 	 case UD_LF_RF:
788  | 			rf_host=convert_rf(attr->value, &rf_type, &rf_port);
789  | 			sprintf(query, query_fmt, tr->thread_upd, tr->object_id, rf_type, rf_host, rf_port);
790  | 			if(rf_host)free(rf_host);
791  | 			break;			
792  |   	 case UD_LF_AY:
793  |                   	sprintf(query, query_fmt, tr->thread_upd, tr->object_id, convert_time(attr->value));
794  |                    	break;		
795  | 	   default:
796  | 		fprintf(stderr, "E:<e_a_u> query not defined for this type of attribute:[%d]\n", attr->type);
797  | 			tr->error|=ERROR_U_BUG;
798  | 			tr->succeeded=0;
799  | 			g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:no update qry\n" ,ERROR_U_BUG, attr->type, attr->value);
800  |     			break;
801  |         }
802  | //fprintf(stderr, "D: update: [%s]", query);
803  | 
804  |     sql_result=SQ_execute_query(SQ_STORE, tr->sql_connection, query);
805  |     num = mysql_affected_rows(tr->sql_connection);
806  | //  fprintf(stderr, "D: query: %d rows affected\n", num);
807  |       if ((num == -1)) {
808  | 	fprintf(stderr, "E:<each_attribute_create> update query:[%d][%s]\n", num, query);
809  | 	tr->error|=ERROR_U_DBS;
810  | 	tr->succeeded=0;
811  | 	g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:update qry\n" ,ERROR_U_DBS, attr->type, attr->value);
812  |       }
813  |       else
814  |       if(num == 0) { // check for duplicates
815  |   		sql_info(tr->sql_connection, sq_info); // REPLACE ... SELECT
816  |   		if ((sq_info[SQL_DUPLICATES]==0) && (sq_info[SQL_MATCHES]==0)) { // this is because of dummies
817  |   	fprintf(stderr, "E: Update: empty query result: [%s]\n", query);
818  |   	tr->error|=ERROR_U_DBS;
819  |   	tr->succeeded=0;
820  |   	g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:null update qry res\n" ,ERROR_U_DBS, attr->type, attr->value);
821  |   		} // else duplicate entry - silently drop it  
822  |       }	
823  |   if (sql_result){ SQ_free_result(sql_result);sql_result=NULL; }
824  |   if (attr->type == A_MO){
825  | //		fprintf(stderr, "D:<e_a_p>: need to auth membership\n");
826  | 		if(auth_member_of(attr, tr)!=0){
827  | 		 tr->error|=ERROR_U_AUT;
828  | 		 tr->succeeded=0;
829  | 		 fprintf(stderr, "E:<each_attribute_create>: membership not allowed\n");
830  | 		 g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:membership not allowed\n" ,ERROR_U_AUT, attr->type, attr->value);	
831  | 		}
832  |   }
833  | //fprintf(stderr, "D:<update_attr>: returning   \n");	
834  | return(0);
835  | }/*  update_attr()  */
836  | 
837  | 
838  | /************************************************************
839  | * each_attribute_proces()                                   *
840  | *                                                           *
841  | * Main function that processes object attributes one by one.*
842  | * Called from g_slist_foreach() function.                   * 
843  | * First it tries to insert an attribute.                    *
844  | * If an error it assumes that attribute is already in       *
845  | * a table and calls update_attr() to update it.             *
846  | * Queries for the attributes are defined in Insert[] array. * 
847  | *                                                           *
848  | * Returns: Nothing. Error code is stored in tr->succeeded.  *
849  | *                                                           *
850  | *************************************************************/
851  | static void each_attribute_process(void *element_data, void *tr_ptr) 
852  | {
853  | SQ_result_set_t * sql_result;
854  | //my_ulonglong num;
855  | int num;
856  | char *query_fmt;
857  | int query_type;
858  | //int dupl;
859  | int do_query;
860  | Attribute_t *attr = element_data;
861  | Transaction_t *tr = (Transaction_t *)tr_ptr;
862  | unsigned int prefix, prefix_length;
863  | unsigned int begin_in, end_in;
864  | int begin_as, end_as;
865  | //GString *query_u;
866  | char query[STR_L];
867  | char * set_name;
868  | char * rf_host; // needs to be deleted after use
869  | int rf_type, rf_port;
870  | gchar *chopped_nh=NULL;
871  | char *a_value;
872  | int sq_info[3];
873  | char *mu_mntner, *mu_prefix;
874  | int dummy_err;
875  | 
876  | static rx_bin_data_t rx_bin_data;
877  | static rx_inum_data_t rx_inum_data;
878  | 
879  | 
880  |   if(tr->succeeded == 0) return; // no sense to continue
881  |   
882  |   do_query=1;
883  |   
884  |   query_type=Insert[attr->type].qtype;
885  | 
886  | /* For loadind pass #1 we need to process only main tables */
887  |   if(tr->load_pass==1){ 
888  | 	switch(query_type) {
889  | 	 case UD_MAIN_:
890  | 	 case UD_MA_U2:
891  | 	 case UD_MA_PR:
892  | 	 case UD_MA_RT:
893  | 	 case UD_MA_IN:
894  | 	 case UD_MA_I6:
895  | 	 case UD_MA_LA:
896  | 	 case UD_MA_AK:
897  | 	 		break;
898  | 	 default:	return;	// return for other than MAIN tables
899  | 	}
900  |   }
901  |   
902  |   query_fmt = Insert[attr->type].qry;
903  | 
904  |   if (strcmp(query_fmt, "") == 0) return;
905  | // fprintf(stderr,"[%d]:[%s]\n", attr->type, attr->value);  
906  |   query_type=Insert[attr->type].qtype;
907  |   switch (query_type) {
908  |    case UD_MAIN_: 
909  |    		if (tr->action==TR_UPDATE) do_query=0;
910  |     		else
911  |     		sprintf(query, query_fmt, tr->thread_ins, tr->object_id, attr->value);
912  |     		break;
913  |    case UD_MA_U2: 
914  |    		if (tr->action==TR_UPDATE) do_query=0;
915  |     		else
916  |     		sprintf(query, query_fmt, tr->thread_ins, attr->value, tr->object_id);
917  |     		if(attr->type == A_OR) {
918  |     			save_rx_orig(&rx_bin_data, attr->value);
919  |     			tr->save = (void *)&rx_bin_data; // just in case
920  |     		}	
921  |     		break;
922  |    case UD_MA_PR: 
923  |    		if (tr->action==TR_UPDATE) do_query=0;
924  |     		else
925  |     		sprintf(query, query_fmt, tr->thread_ins, tr->class_type, tr->object_id,  attr->value);
926  |     		break;	
927  |    case UD_MA_RT:
928  |     		if (tr->action==TR_UPDATE) do_query=0;
929  |     		else {
930  |     		  expand_rt(attr->value, &prefix, &prefix_length);
931  | 		//fprintf(stderr, "D: route: %u/%u\n", prefix, prefix_length);     		
932  |     		sprintf(query, query_fmt, tr->thread_ins,  
933  | 	    		tr->object_id, prefix, prefix_length);
934  | 	    	// save stuff for radix update
935  | 	    	  save_rx_pref(&rx_bin_data, prefix, prefix_length);
936  | 	    	  tr->save = (void *)&rx_bin_data;
937  | 	    	}
938  |     		break;
939  |    case UD_MA_IN:
940  |     		if (tr->action==TR_UPDATE) do_query=0;
941  |     		else {
942  |     		  convert_in(attr->value, &begin_in, &end_in);
943  | 		  sprintf(query, query_fmt, tr->thread_ins, tr->object_id, begin_in, end_in);
944  | 		  save_rx_rang(&rx_inum_data, begin_in, end_in);
945  | 		  tr->save = (void *)&rx_inum_data;
946  | 		}	
947  |     		break;
948  |    case UD_MA_I6:
949  |     		break;	
950  |    case UD_MA_LA: // save the new value for commit
951  |             	tr->save=attr->value;
952  | //            	fprintf(stderr, "D:<e_a_p> attribute saved: %s\n", tr->save);
953  |             	return;
954  |             	break;
955  |    case UD_MA_AK:
956  |    		if (tr->action==TR_UPDATE) do_query=0;
957  |    		else {
958  |    		  convert_as_range(attr->value, &begin_as, &end_as);
959  | 		  sprintf(query, query_fmt, tr->thread_ins, tr->object_id, begin_as, end_as);
960  |    		}
961  |    		break;         	    		
962  |    case UD_AUX__: 
963  |     		a_value = attr->value;
964  |     		if((attr->type==A_AC) || (attr->type==A_TC) || (attr->type==A_ZC))
965  |     		 if(strlen(attr->value)>MAX_NIC_HDL){
966  |     			chopped_nh = g_strndup(attr->value, MAX_NIC_HDL);
967  |     			a_value=chopped_nh;
968  |     		 } 
969  |     		sprintf(query, query_fmt, tr->thread_ins, tr->object_id, tr->class_type, a_value);
970  |     		if(tr->dummy!=1)strcat(query, " AND dummy=0 ");
971  | 	    	if(chopped_nh){ free(chopped_nh); chopped_nh=NULL;}
972  |     		break;
973  |    case UD_AX_MO:
974  |     		set_name = get_set_name(tr->class_type);
975  | //    		fprintf(stderr, "D: retrieved set name: %s\n", set_name);
976  |     		sprintf(query, query_fmt, tr->thread_ins,  
977  | 	    	 tr->object_id, set_name, tr->class_type, set_name, set_name, set_name, attr->value);
978  |     		break;	
979  |    case UD_AX_MR:
980  |       		if ((strcmp(attr->value, "ANY")==0) || (strcmp(attr->value, "any")==0) || (strcmp(attr->value, "Any")==0))
981  |       		 sprintf(query, query_fmt, tr->thread_ins, tr->object_id, tr->class_type, "ANY");
982  |       		else  
983  |       		 sprintf(query, query_fmt, tr->thread_ins, tr->object_id, tr->class_type, attr->value);
984  | 		break;	
985  |    case UD_AX_MU:
986  |    		a_value=g_strdup(attr->value);
987  |    		mu_mntner=s_splitn(a_value, 1);
988  |    		mu_prefix=s_splitn(a_value, 1);
989  |    		sprintf(query, query_fmt, tr->thread_ins, tr->object_id, mu_prefix, tr->class_type, mu_mntner);
990  |    		free(a_value);
991  |    		if(tr->dummy!=1)strcat(query, " AND dummy=0 ");
992  |    		break;
993  |    case UD_LEAF_: 
994  |     		sprintf(query, query_fmt, tr->thread_ins, tr->object_id, attr->value);
995  |     		break;
996  |    case UD_LF_OT:
997  |    		sprintf(query, query_fmt, tr->thread_ins, tr->object_id, tr->class_type, attr->value);
998  |    		break; 		    		
999  |    case UD_LF_AT: // check PGPKEY. If yes - check the existence of key-cert.
1000 |       		if(tr->dummy!=1){
1001 |       		 if(strncmp("PGPKEY", attr->value, 6)==0) {
1002 |       			if(get_ref_id(tr, "key_cert", "key_cert", attr->value, NULL)<=0) { 
1003 |       				fprintf(stderr, "E:<e_a_p>: No key-cert object.\n");
1004 |       				tr->error|=ERROR_U_OBJ;
1005 |       				tr->succeeded=0;
1006 |       				g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:no key-cert object\n" ,ERROR_U_OBJ, attr->type, attr->value);
1007 |       				return;
1008 |       			}
1009 |       		 }
1010 |       		} 
1011 |       		sprintf(query, query_fmt, tr->thread_ins, tr->object_id, tr->class_type, attr->value);
1012 |       		break;      
1013 |    case UD_LF_IF:
1014 |     		// Convert ascii ip -> numeric one
1015 |     		convert_if(attr->value, &prefix);
1016 |     		sprintf(query, query_fmt, tr->thread_ins, tr->object_id, prefix);
1017 |     		break;
1018 |    case UD_LF_RF:
1019 |     		rf_host=convert_rf(attr->value, &rf_type, &rf_port);
1020 |     		sprintf(query, query_fmt, tr->thread_ins, 0 /*tr->object_id*/ , rf_type, rf_host, rf_port);
1021 |     		if(rf_host)free(rf_host);
1022 |     		break;	
1023 |    case UD_LF_AY:
1024 |    		sprintf(query, query_fmt, tr->thread_ins, tr->object_id, convert_time(attr->value));
1025 |    		break;
1026 |     	default:
1027 | fprintf(stderr, "E: query not defined for this type of attribute\n");
1028 |     		break;
1029 |   }
1030 |   
1031 | //fprintf(stderr, "D: insert: [%s]", query);
1032 | 
1033 |   if(do_query){
1034 |    sql_result=SQ_execute_query(SQ_STORE, tr->sql_connection, query);
1035 |    num = mysql_affected_rows(tr->sql_connection);
1036 |    if (sql_result)SQ_free_result(sql_result);sql_result=NULL;    
1037 |   } 
1038 |   else {
1039 |    update_attr(attr, tr);
1040 |    return;
1041 |   }
1042 |   
1043 | //  fprintf(stderr, "D: query: %d rows affected\n", num);
1044 | 
1045 |   if(num>0){ // this is OK
1046 | // if attr=="member_of" we need additional processing
1047 | 	if (attr->type == A_MO){
1048 | //		fprintf(stderr, "D:<e_a_p>: need to auth membership\n");
1049 | 		if(auth_member_of(attr, tr)!=0){
1050 | 		 tr->error|=ERROR_U_AUT;
1051 | 		 tr->succeeded=0;
1052 | 		 fprintf(stderr, "E:<each_attribute_create>: membership not allowed\n");
1053 | 		 g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:membership not allowed\n" ,ERROR_U_AUT, attr->type, attr->value);	
1054 | 		}
1055 | 	}
1056 | 	return;
1057 |   }
1058 | 
1059 |   if(num == -1){ // if not update that is the  error condition. free resources and return (except some attributes)
1060 |   	if (tr->action==TR_UPDATE) {
1061 |   		update_attr(attr, tr);
1062 |   		return;
1063 |   	}	
1064 |   	else { 
1065 |   		switch(attr->type) {
1066 |   		case A_EM: break; // duplicate e-mail:
1067 |   		case A_PN: break; // fe: Antony Antony
1068 |   		case A_RO: break; // fe: IB og Co Reklame og Marketing
1069 |   		
1070 |   		default:
1071 |  // !!!!!!!! tr->succeeded=0; fprintf(stderr, "E: query returned an error: [%s]\n", query->str);
1072 |   			break;
1073 |   		}
1074 |   	}
1075 |   }
1076 |   else
1077 |   if(num == 0) { 
1078 |   	sql_info(tr->sql_connection, sq_info);
1079 |   	if (sq_info[SQL_DUPLICATES]>0) { // update attribute
1080 |   		if (sq_info[SQL_DUPLICATES]>1) { // this is an error - more that 1 duplicate
1081 |   			fprintf(stderr, "E: Update: Too many duplicates for query: [%s]\n", query);
1082 |   			tr->error|=ERROR_U_DBS;
1083 |   			tr->succeeded=0;
1084 |   			g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:duplicates\n" ,ERROR_U_DBS, attr->type, attr->value);
1085 |   			return;
1086 |   		}
1087 |   		update_attr(attr, tr);
1088 |   	}
1089 |   	else { // try to create dummy and repeat query
1090 |   		
1091 | //		fprintf(stderr, "W: no ref. integrity. Trying to create dummy...");
1092 | 
1093 | 		dummy_err = create_dummy(attr, tr);
1094 | 		if (dummy_err == 0) {
1095 | //			fprintf(stderr, "D: ... dummy OK\n");
1096 | 			g_string_sprintfa(tr->error_script,"W[%d][%d:%s]:dummy created\n" ,0, attr->type, attr->value);
1097 | //			fprintf(stderr, "D: repeating query: %s\n", query);
1098 | 			sql_result=SQ_execute_query(SQ_STORE, tr->sql_connection, query);
1099 | 			num = mysql_affected_rows(tr->sql_connection);
1100 | 			if (sql_result) { SQ_free_result(sql_result); sql_result=NULL;}
1101 | 			if ((num == -1) || (num==0)) {
1102 | 			  tr->error|=ERROR_U_DBS;
1103 | 			  tr->succeeded=0;
1104 | 			  fprintf(stderr, "E:<each_attribute_create>: insert query: [%s]\n", query);
1105 | 			  g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:insert qry\n" ,ERROR_U_DBS, attr->type, attr->value);
1106 | 			}
1107 | 		}
1108 | 		else 
1109 | 		 if(dummy_err == 1) {
1110 | 		   tr->error |= ERROR_U_OBJ;
1111 | 		   tr->succeeded=0;
1112 | 		   g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:rf failure\n" ,ERROR_U_OBJ, attr->type, attr->value);
1113 | 		 }
1114 | 		 else {
1115 | 		   tr->error|=ERROR_U_DBS;
1116 | 		   tr->succeeded=0;
1117 | 		   fprintf(stderr, "E:<each_attribute_create>: dummy not created\n");
1118 | 		   g_string_sprintfa(tr->error_script,"E[%d][%d:%s]:dummy not created\n" ,ERROR_U_DBS, attr->type, attr->value);
1119 | 		}	
1120 |   	}// RI
1121 |   }// if num == 0
1122 |   return;
1123 | } /* each_attribute_process() */
1124 | 
1125 | 
1126 | 
1127 | /************************************************************
1128 | * each_primary_key_select()                                 *
1129 | *                                                           *
1130 | * Function that forms a query for an object (w prinary keys)*
1131 | * Called from g_slist_foreach() function.                   *
1132 | * Primary keys are defined in Select[] array.               *
1133 | *                                                           *
1134 | * Returns: Nothing. Error code is stored in tr->succeeded.  *
1135 | *                                                           *
1136 | *************************************************************/ 
1137 | static void each_primary_key_select(void *element_data, void *result_ptr) 
1138 | {
1139 | Attribute_t *attr = element_data;
1140 | GString *result = (GString *)result_ptr;
1141 | char *query_fmt;
1142 | unsigned int prefix, prefix_length;
1143 | unsigned int begin_in, end_in;
1144 | int begin_as, end_as;
1145 |   
1146 |   query_fmt = Select[attr->type].qry;
1147 | 
1148 | // fprintf(stderr, "D: qry fmt: %s\n", query_fmt);
1149 | 
1150 |   if (strcmp(query_fmt, "") != 0) {
1151 |     switch (Select[attr->type].qtype) {
1152 |      case UD_MAIN_: 
1153 |      		g_string_sprintfa(result, query_fmt, attr->value);
1154 |     		break;
1155 |      case UD_MA_RT:
1156 |     		expand_rt(attr->value, &prefix, &prefix_length);
1157 |     		g_string_sprintfa(result, query_fmt, prefix, prefix_length);
1158 |     		break;
1159 |      case UD_MA_IN:
1160 | 		convert_in(attr->value, &begin_in, &end_in);
1161 | 		g_string_sprintfa(result, query_fmt, begin_in, end_in);
1162 |     		break;
1163 |      case UD_MA_AK:
1164 |      		convert_as_range(attr->value, &begin_as, &end_as);
1165 |      		g_string_sprintfa(result, query_fmt, begin_as, end_as);
1166 | 		break;
1167 |      default:
1168 | fprintf(stderr, "E:<e_p_k_s>: query not defined for this type of attribute:[%d]\n", attr->type);
1169 | 
1170 | 
1171 |     	break;
1172 |     } 
1173 | //fprintf(stderr, "D: each_primary_key_select(): %s\n",result->str);    
1174 |   }
1175 | } 
1176 | 
1177 | /************************************************************
1178 | * perform_create(const Object_t *obj, Transaction_t *tr)    * 
1179 | *                                                           *
1180 | * Procedure for creating a new object.                      *
1181 | * First inserts object into 'last' table and gets object_id.*
1182 | * Then processes all attributes.                            *
1183 | *                                                           *
1184 | * Returns: Nothing. Error code is stored in tr->succeeded.  *
1185 | *                                                           *
1186 | *************************************************************/ 
1187 | static int perform_create(Transaction_t *tr) 
1188 | {
1189 |  Object_t *obj=tr->object;
1190 |  SQ_result_set_t *sql_result;
1191 |  char *str;
1192 |  static char query[STR_XXXL];
1193 |  int  num;
1194 |  long timestamp;
1195 |   
1196 |       str = (obj->object)->str;
1197 |       timestamp=time(NULL);
1198 |       sprintf(query, "INSERT INTO last SET thread_id=%d, timestamp=%ld, object_type=%d, object='%s' ",
1199 |       	             tr->thread_ins, timestamp, tr->class_type, str);
1200 | 
1201 |       sql_result=SQ_execute_query(SQ_STORE, tr->sql_connection, query);
1202 |       num = mysql_affected_rows(tr->sql_connection);
1203 |       if (sql_result)SQ_free_result(sql_result);
1204 |       if ((num == -1) || (num == 0)) {
1205 |         fprintf(stderr, "E ERROR!<perform_create>: INSERT last failed:%d\n", num);
1206 |         tr->error|=ERROR_U_DBS;
1207 |         tr->succeeded=0;
1208 |         g_string_sprintfa(tr->error_script,"E[%d][:]:INSERT last failed\n" ,ERROR_U_DBS);
1209 |       }
1210 |       else {
1211 |         tr->object_id=mysql_insert_id(tr->sql_connection);
1212 |         g_slist_foreach(obj->attributes, each_attribute_process, tr);
1213 |       }
1214 |     return(0);  
1215 | } /* perform_create() */
1216 | 
1217 | /************************************************************
1218 | * perform_update(Transaction_t *tr)                         * 
1219 | *                                                           *
1220 | * Procedure for updating (existing) object.                 *
1221 | * First processes all attributes.                           *
1222 | * Then saves previous object in 'history' and updates       *
1223 | * 'last' table.                                             *
1224 | *                                                           *
1225 | * Returns: Nothing. Error code is stored in tr->succeeded.  *
1226 | *                                                           *
1227 | *************************************************************/ 
1228 | static int perform_update(Transaction_t *tr) 
1229 | {
1230 | Object_t *obj=tr->object;
1231 | SQ_result_set_t * sql_result;
1232 | char *str;
1233 | char str_id[STR_M];
1234 | char *sql_str;
1235 | static char query[STR_XXXL];
1236 | int num;
1237 | long sequence_id;
1238 | long timestamp;
1239 | 
1240 |   /* process each attribute one by one */
1241 |   g_slist_foreach(obj->attributes, each_attribute_process, tr);
1242 | 
1243 |   /* If we've already failed or this is fast load - just return */
1244 |   if((tr->succeeded == 0) || (tr->load_pass != 0)) return(0);
1245 |   
1246 |     /* No return: thread_id=0 */
1247 |     /* Do it only if previous transactions finished well */
1248 |        
1249 |     /* copy object to the history table */
1250 | fprintf(stderr, "INSERT history\n");    
1251 |     sprintf(query,"INSERT history "
1252 |                   "SELECT 0, object_id, sequence_id, timestamp, object_type, object "
1253 |                   "FROM last "
1254 |                   "WHERE object_id=%ld ", tr->object_id);
1255 | 
1256 |     sql_result=SQ_execute_query(SQ_STORE, tr->sql_connection, query);
1257 |     num = mysql_affected_rows(tr->sql_connection);
1258 |     if (sql_result)SQ_free_result(sql_result);
1259 |     if ((num == -1) || (num == 0)) {
1260 |          fprintf(stderr, "E ERROR!<perform_update>: INSERT history failed:[%d][%s]\n", num, query);
1261 |          tr->error|=ERROR_U_DBS;
1262 |          tr->succeeded=0;
1263 |          g_string_sprintfa(tr->error_script,"E[%d][:]:INSERT history failed\n" ,ERROR_U_DBS);
1264 |          return(-1);
1265 |     }
1266 | 
1267 |     /* get sequence number */
1268 | //fprintf(stderr, "get seq\n");    
1269 |     sprintf(str_id, "%ld", tr->object_id);
1270 |     sql_str= get_field_str(tr, "sequence_id", "last", "object_id", str_id, NULL);
1271 |     if(sql_str) {
1272 |        	  sequence_id = atol(sql_str);
1273 |        	  free(sql_str);
1274 |     }
1275 |     else {
1276 |        	 fprintf(stderr, "E ERROR!<perform_update> cannot get sequence_id: %d\n", num);
1277 |        	 tr->error|=ERROR_U_DBS;
1278 |          tr->succeeded=0;
1279 |          g_string_sprintfa(tr->error_script,"E[%d][:]:cannot get seq ID\n" ,ERROR_U_DBS);
1280 |          return(-1);
1281 |     }
1282 |    
1283 |     tr->sequence_id=sequence_id; // save it for rollback
1284 |         
1285 |        
1286 |     /* insert new version into the last */
1287 |     str = (obj->object)->str;
1288 |     timestamp=time(NULL);
1289 |     sequence_id++;
1290 |        
1291 | //fprintf(stderr, "UPDATE last\n");       
1292 |     /* If we are here - it's almost commit. Otherwise this row will not be updated at all. */
1293 |     sprintf(query, "UPDATE last "
1294 |                    "SET thread_id=0, sequence_id=%ld, timestamp=%ld, object_type=%d, object='%s' "
1295 |                    "WHERE object_id=%ld ",
1296 |                    sequence_id, timestamp, tr->class_type, str, tr->object_id);
1297 | 
1298 |     sql_result=SQ_execute_query(SQ_STORE, tr->sql_connection, query);
1299 |     num = mysql_affected_rows(tr->sql_connection);
1300 |     if (sql_result)SQ_free_result(sql_result);
1301 |     if ((num == -1) || (num == 0)) {
1302 |          fprintf(stderr, "E ERROR!<perform_update>: INSERT last failed: [%d][%s]\n", num, query);
1303 |          tr->error|=ERROR_U_DBS;
1304 |          tr->succeeded=0;
1305 |          g_string_sprintfa(tr->error_script,"E[%d][:]:INSERT last failed\n" ,ERROR_U_DBS);
1306 |          return(-1);
1307 |     }
1308 |  return(0);   
1309 | } /* perform_update() */
1310 | 
1311 | 
1312 | 
1313 | 
1314 | /************************************************************
1315 | * int object_process(Transaction_t *tr)                     *
1316 | *                                                           *
1317 | * This is the interface between core and upper layer        *
1318 | * All it gets is Transaction *tr, which contains all        *
1319 | * necessary information, including the object in its        *
1320 | * internal representation.                                  *
1321 | *                                                           *
1322 | * Returns: Nothing. Error code is stored in tr->succeeded.  *
1323 | *                                                           *
1324 | *************************************************************/ 
1325 | int object_process(Transaction_t *tr) 
1326 | {
1327 | 	
1328 | /* not supported */
1329 |  if(tr->class_type==C_I6) { 
1330 |    tr->succeeded=0; tr->error |= ERROR_U_NSUP;
1331 |    fprintf(stderr, "Object type currently not supported\n");
1332 |    return(-1);
1333 |  }  
1334 | 	
1335 | 	switch(tr->action){
1336 | 	 case TR_DELETE:
1337 | 	 	fprintf(stderr, "D: Action: Delete...");
1338 | 	 	printf("\tD: Action: Delete...");
1339 | 	 	delete(tr);
1340 | 	 	return(0); //commit is not needed
1341 | 	 	break;
1342 | 	 	
1343 | 	 case TR_UPDATE:
1344 | 	 	fprintf(stderr, "D: Action: Update...");
1345 | 	 	printf("\tD: Action: Update...");
1346 | 	 	perform_update(tr);
1347 | 	 	break;
1348 | 	 	
1349 | 	 case TR_CREATE:
1350 | 	 	fprintf(stderr, "D: Action: Create...");
1351 | 	 	printf("\tD: Action: Create...");
1352 | 	 	perform_create(tr);
1353 | 	 	break;
1354 | 	 	
1355 | 	 default:
1356 | 	 	fprintf(stderr, "D: Action: Unknown...");
1357 | 	 	tr->succeeded=0;
1358 | 	 	tr->error|=ERROR_U_BADOP;
1359 | 	 	return(-1);
1360 | 	 	break;
1361 | 	} 
1362 |    if(tr->load_pass == 0) { // not for fast loader
1363 |       if (tr->succeeded == 1) {
1364 | //fprintf(stderr, "D: Commit transaction...\n");      
1365 |         commit(tr);
1366 | 	return(0);
1367 |       }
1368 |       else {
1369 | //fprintf(stderr, "D: Roll back transaction...\n");      
1370 |         rollback(tr);
1371 |         return(0);
1372 |       }
1373 |     }  
1374 |  return(0);   
1375 | } /* object_process() */
1376 |