1    | /***************************************
2    |   $Revision: 1.9 $
3    | 
4    |   Status: NOT REVUED, NOT TESTED
5    | 
6    |  Author(s):       Andrei Robachevsky
7    | 
8    |   ******************/ /******************
9    |   Modification History:
10   |         andrei (10/04/2000) Created.
11   |   ******************/ /******************
12   |   Copyright (c) 2000                              RIPE NCC
13   |  
14   |   All Rights Reserved
15   |   
16   |   Permission to use, copy, modify, and distribute this software and its
17   |   documentation for any purpose and without fee is hereby granted,
18   |   provided that the above copyright notice appear in all copies and that
19   |   both that copyright notice and this permission notice appear in
20   |   supporting documentation, and that the name of the author not be
21   |   used in advertising or publicity pertaining to distribution of the
22   |   software without specific, written prior permission.
23   |   
24   |   THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
25   |   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
26   |   AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
27   |   DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
28   |   AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
29   |   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
30   |  ***************************************/
31   | #include <glib.h>
32   | #include <stdio.h>
33   | #include <strings.h>
34   | #include <glib.h>
35   | #include <stdlib.h>
36   | #include <ctype.h>
37   | #include <unistd.h>
38   | 
39   | #include "nh.h"
40   | #include "memwrap.h"
41   | #include "stubs.h"
42   | 
43   | /*+ String sizes +*/
44   | #define STR_S   63
45   | #define STR_M   255
46   | #define STR_L   1023
47   | #define STR_XL  4095
48   | #define STR_XXL 16383
49   | #define STR_XXXL 65535
50   | 
51   | /*
52   | CREATE TABLE nic_hdl (
53   |   thread_id(11) DEFAULT '0' NOT NULL,
54   |   range_id int(10) unsigned DEFAULT '0' NOT NULL auto_increment, 
55   |   range_start int(10) DEFAULT '0' NOT NULL,
56   |   range_end int(10) DEFAULT '0' NOT NULL,
57   |   space char(4) DEFAULT '' NOT NULL,
58   |   source char(10) DEFAULT '' NOT NULL,
59   |   PRIMARY KEY (range_id, range_start, range_end)
60   | );
61   | 
62   | */
63   | 
64   | #define get_min_range(prange, sql_connection) get_range(MIN_NIC_ID, prange, sql_connection)
65   | static long get_range(long nic_id, range_t *prange, SQ_connection_t *sql_connection);
66   | static long update_range(long range_id, range_t *p_newrange, SQ_connection_t *sql_connection, int commit_now);
67   | static long create_range(range_t *p_range, SQ_connection_t *sql_connection, int commit_now);
68   | 
69   | /************************************************************
70   | * int NH_convert()                                          *
71   | *                                                           *
72   | * Converts space & nic_id into a database nic-handle        *
73   | *                                                           *
74   | * Returns:                                                  *
75   | * The newly allocated string containing nic handle          *
76   | * The string should be freed when no longer used            *
77   | *                                                           *
78   | * NULL in case of failure                                   *
79   | *                                                           *
80   | ************************************************************/
81   | char *NH_convert(nic_handle_t *nh_ptr)
82   | {
83   |  char *nic_id=NULL;
84   |  char *nic_components[4];
85   |  char *nic_handle;
86   |  int nc=0;
87   |   /* Check for special cases */
88   |   /* Is is and AUTO nic-handle ? */
89   |   if(nh_ptr->nic_id == AUTO_NIC_ID) return(NULL);
90   |   if(nh_ptr->space) {
91   | 	  nic_components[nc]=nh_ptr->space; nc++;
92   |   }
93   |   /* No nic-id ? */
94   |   if(nh_ptr->nic_id != NULL_NIC_ID) { 
95   | 	  nic_id = g_strdup_printf("%ld", nh_ptr->nic_id);
96   | 	  nic_components[nc]=nic_id; nc++;
97   |   }
98   | 	  
99   |   /* No source ? */
100  |   if (nh_ptr->source) {
101  | 	  nic_components[nc]=nh_ptr->source; nc++;
102  |   }
103  |   nic_components[nc]=NULL;
104  |   nic_handle = g_strjoinv(NULL, nic_components);
105  |   UT_free(nic_id);
106  |   return(nic_handle);
107  | }
108  | 
109  | /************************************************************
110  | * int NH_parse()                                            *
111  | *                                                           *
112  | * Parse a nic handle as supplied by DBupdate                *
113  | * The format is: <space>[<nic_id>|*][SOURCE]                *
114  | * Also extracts nic_id and space for regular nic-handles    *
115  | *                                                           *
116  | * Acceptable format is:                                     *
117  | * [A-Z][A-Z]*[1-9][0-9]*(-[A-Z][A-Z]*)?                     *
118  | *                                                           *
119  | * Returns:                                                  *
120  | * >0 - success                                              *
121  | *  0 - AUTO NIC                                             *
122  | * -1  - error (not defined and processed yet)               *
123  | *                                                           *
124  | ************************************************************/
125  | int NH_parse(char *nic, nic_handle_t **nh_ptr_ptr)
126  | {
127  | char *ptr;
128  | int res = 1;
129  | nic_handle_t *nh_ptr;
130  | 
131  |      if(!(nh_ptr=calloc(1, sizeof(nic_handle_t)))) die;
132  |      
133  |      ptr=nic;	
134  | 
135  |      /* extract space */
136  |      while(isalpha((int)*ptr))ptr++;
137  |      if(!(nh_ptr->space=malloc(ptr-nic+1))) die;
138  |      strncpy(nh_ptr->space, nic, ptr-nic); *(nh_ptr->space+(ptr-nic))='\0';
139  | 
140  |      /* If there are no digits, then this is no nic-hdl */
141  |      /* We reserve NULL_NIC_ID for such pretty identifiers */
142  |      if(*ptr == '\0') {
143  |        nh_ptr->nic_id=NULL_NIC_ID;
144  |        nh_ptr->source=NULL;
145  |      }
146  |      else {
147  |        /* Check if it is and AUTO nic */
148  |        if (*ptr == '*') {
149  | 	       /* For AUTO nic_id we reserve AUTO_NIC_ID */
150  | 	       nh_ptr->nic_id=AUTO_NIC_ID;
151  | 	       res=0;
152  | 	       ptr++;
153  |        } else {
154  |          nic=ptr;
155  | 	 /* convert digits (if any) and store first invalid characted in ptr */
156  |          nh_ptr->nic_id=(int)strtol(nic, &ptr, 10);
157  | 	 /* Check if there were any digits at all */
158  | 	 if(ptr == nic) nh_ptr->nic_id=NULL_NIC_ID;
159  |        }
160  |        /* check if there is any suffix */
161  |        if (*ptr == '\0') nh_ptr->source=NULL;
162  |        /* Copy suffix into source */
163  |        else {
164  | 	 if(!(nh_ptr->source=malloc(strlen(ptr)+1))) die;
165  | 	 strcpy(nh_ptr->source, ptr);
166  |        }
167  |      } 
168  |      *nh_ptr_ptr=nh_ptr;
169  |      return(res);
170  | }
171  | 
172  | 
173  | 
174  | /************************************************************
175  | * int NH_check()                                            *
176  | *                                                           *
177  | * Check a NIC handle in the repository                      *
178  | *                                                           *
179  | *                                                           *
180  | * Returns:                                                  *
181  | *  1 - success                                              *
182  | *  0 - error(nic_id exists or space is fully occupied)      *
183  | * -1 - error (f.e. more than one object with the same PK)   *
184  | *                                                           *
185  | ************************************************************/
186  | int NH_check(nic_handle_t *nh_ptr, SQ_connection_t *sql_connection)
187  | {
188  | range_t range;
189  | long range_id;
190  | long nic_id=nh_ptr->nic_id;
191  | 
192  | 
193  |   range.space=nh_ptr->space;
194  |   if(nh_ptr->source)range.source=nh_ptr->source; else range.source="";
195  |   
196  |   if (nic_id == AUTO_NIC_ID) {
197  |   /* NIC handle is an AUTO one */
198  |   /* get first range (with min range_end) for a given space */
199  |    range_id = get_min_range(&range, sql_connection); 
200  |    if(range_id<0)  return(-1); /* in case of an error */
201  | 
202  |    if ( range_id==0 ) {
203  |   /* Nothing found */
204  |   /* Allocate a hic-hdl in a new space with the first range {0-1} in it*/
205  |  	nic_id=1;
206  |    } else {
207  |       if ( range.end == MAX_NIC_ID ) return(0); /* space is fully occupied  */
208  |       /* attach to range and may be join with next */
209  |        nic_id = range.end+1;
210  |    }
211  |   }
212  | /* if not AUTO */  
213  |   else {
214  |     range_id = get_range(nic_id, &range, sql_connection);
215  |     if(range_id <0)  return(-1); /* in case of an error */
216  |     if(range_id!=0)  return(0); /* this nic_id already exists */
217  |   }
218  |   nh_ptr->nic_id=nic_id;
219  |  return(1); 
220  | }
221  | 
222  | /************************************************************
223  | * long NH_free()                                             *
224  | *                                                           *
225  | * Delete a NIC handle from the repository                   *
226  | *                                                           *
227  | * To finalize changes make commit/rollback                  *
228  | *                                                           *
229  | * Returns:                                                  *
230  | *  1 - success                                              *
231  | *  0 - error (range is not founnd)                          *
232  | * -1 - error (f.e. more than one object with the same PK)   *
233  | *                                                           *
234  | ************************************************************/
235  | int NH_free(nic_handle_t *nh_ptr, SQ_connection_t *sql_connection, int commit_now)
236  | {
237  | range_t range;
238  | long range_id;
239  | int old_start;
240  | long nic_id=nh_ptr->nic_id;
241  | 
242  | 
243  |   range.space=nh_ptr->space;
244  |   if(nh_ptr->source)range.source=nh_ptr->source; else range.source="";
245  |   
246  |   /* Search for the range containing the nic-handle */
247  |   range_id = get_range(nic_id, &range, sql_connection);
248  |   /* If range is not found or an error occcured - return */
249  |   if(range_id==0) { return(0); }
250  |   if(range_id<0)  { return(-1); }
251  |   
252  |   if(nic_id == range.start) {
253  |   /* update range start and may be detele range and space */
254  |    range.start+=1;
255  |    range_id=update_range(range_id, &range, sql_connection, commit_now);
256  |    if(range_id<=0) {  return(-1); }
257  |   }
258  |   else if(nic_id == range.end) { 
259  |   /* update range end and may be detele range and space */
260  |          range.end-=1;
261  |          range_id=update_range(range_id, &range, sql_connection, commit_now);
262  | 	 if(range_id<=0) {  return(-1); }
263  |   }
264  |   else { 
265  |        /* split the range into two */ 
266  |        /* shrink the old one */
267  |          old_start=range.start;
268  |          range.start=nic_id+1;
269  |          range_id=update_range(range_id, &range, sql_connection, commit_now);
270  | 	 if(range_id<=0) { return(-1); }
271  |        /* create a new one */
272  |          range.start=old_start;
273  |          range.end=nic_id-1;
274  |          range_id=create_range(&range, sql_connection, commit_now);
275  | 	 if(range_id<=0) {  return(-1); }
276  |   }
277  |   
278  |   return(1);
279  | }
280  | 
281  | 
282  | /************************************************************
283  | * int NH_register()                                         *
284  | *                                                           *
285  | * Get a NIC handle from the repository                      *
286  | *                                                           *
287  | *                                                           *
288  | * Returns:                                                  *
289  | * 1 - success                                               *
290  | * 0  - nic_id already exists or space is fully occupied     *
291  | * -1 - error (f.e. more than one object with the same PK)   *
292  | *                                                           *
293  | ************************************************************/
294  | int NH_register(nic_handle_t *nh_ptr, SQ_connection_t *sql_connection, int commit_now)
295  | {
296  | range_t range;
297  | long range_id;
298  | long nic_id=nh_ptr->nic_id;
299  | 
300  | 
301  | 
302  | 
303  |  /* Yiu should check for nh first for AUTO nic-handles */
304  |   if (nic_id == AUTO_NIC_ID) { return(0); };
305  | 
306  |   range.space=nh_ptr->space;
307  |   if(nh_ptr->source)range.source=nh_ptr->source; else range.source="";
308  | 
309  |   range_id = get_range(nic_id, &range, sql_connection);
310  |   if(range_id <0)  { return(-1); } /* in case of an error */
311  |   if(range_id!=0)  { return(0); } /* this nic_id already exists */
312  |  
313  |   /* check if we can attach to existing next range */
314  |   range_id = get_range(nic_id+1, &range, sql_connection);
315  |   if(range_id <0)  { return(-1); } /* in case of an error */
316  | 
317  |     if( range_id>0 ) { 
318  |     /* attach to range and may be join with previous */ 
319  |      range.start-=1;
320  |      range_id=update_range(range_id, &range, sql_connection, commit_now);
321  |      if(range_id<=0) { return(-1); }
322  |     }
323  |     else {
324  |      /* check if we can attach to existing previous range */
325  |       if(nic_id>0) range_id = get_range(nic_id-1, &range, sql_connection);
326  |       else range_id=0; /* there is no previous range in this case (nic_id==0) */
327  |       if(range_id <0)  { return(-1); } /* in case of an error */
328  |       if( range_id>0 ) { 
329  |       /* attach to range and may be join with next */
330  |        range.end+=1;
331  |        range_id=update_range(range_id, &range, sql_connection, commit_now);
332  |        if(range_id<=0) { return(-1); }
333  |       }
334  |       else {
335  |        /* If we cannot attach to any existing range - create new {nic_id-nic_id} */
336  |        range.end=range.start=nic_id;
337  |        range_id=create_range(&range, sql_connection, commit_now);
338  |        if(range_id <=0)  { return(-1); } /* in case of an error */
339  |       }
340  |     }  
341  |  return(1);
342  | }
343  | 
344  | /*
345  |  Free nic_handle_t structure 
346  |  */
347  | void free_nh(nic_handle_t *nh_ptr)
348  | {
349  |  if(nh_ptr){
350  |    if(nh_ptr->space)free(nh_ptr->space);
351  |    if(nh_ptr->source)free(nh_ptr->source);
352  |    free(nh_ptr);
353  |  }
354  | }
355  | 
356  | 
357  | /************************************************************
358  | * long get_range()                                          *
359  | *                                                           *
360  | * Searches for the range of the space containing            *
361  | * the specified nic_id                                      *
362  | *                                                           *
363  | * To request to search for the firt (min) range, nic_id     *
364  | * should be set to MIN_NIC_ID                               *
365  | *                                                           *
366  | * Returns:                                                  *
367  | * >0 - range exists, returns range_id                       *
368  | * 0  - range does not exist                                 *
369  | * -1 - DB error (f.e. more than one object with the same PK)*
370  | *                                                           *
371  | * **********************************************************/
372  | static long get_range(long nic_id, range_t *prange, SQ_connection_t *sql_connection)
373  | {
374  | SQ_result_set_t *sql_result;
375  | SQ_row_t *sql_row;
376  | char *sql_str;
377  | GString *query;
378  | long range_id=0;
379  | int sql_err;
380  | 
381  |  if ((query = g_string_sized_new(STR_L)) == NULL){ 
382  |   fprintf(stderr, "E: cannot allocate gstring\n"); 
383  |   return(-1); 
384  |  }
385  |  
386  | /* Define row numbers in the result of the query */
387  | #define RANGE_ID 0
388  | #define RANGE_START 1
389  | #define RANGE_END 2
390  |  
391  |  if (nic_id==MIN_NIC_ID) {
392  |   /* requesting the first (min) range */
393  |   g_string_sprintf(query, "SELECT range_id, range_start, range_end " 
394  |                           "FROM nic_hdl "
395  |                           "WHERE space='%s' "
396  | 			  "AND source='%s' "
397  |                           "AND (range_start=0 "
398  |                           "OR  range_start=1) ",
399  | 			  prange->space, prange->source);
400  |  } else {
401  | 
402  |   g_string_sprintf(query, "SELECT range_id, range_start, range_end " 
403  |                           "FROM nic_hdl "
404  |                           "WHERE space='%s' "
405  | 			  "AND source='%s' "
406  |                           "AND range_start<=%ld "
407  |                           "AND range_end>=%ld ",
408  | 			  prange->space, prange->source, nic_id, nic_id);
409  |  }
410  |         
411  | /* execute query */
412  | /* fprintf(stderr, "get_range[%s]\n", query->str); */
413  |  sql_err=SQ_execute_query(sql_connection, query->str, &sql_result);
414  |  g_string_free(query, TRUE);
415  |  
416  |  if(sql_err) {
417  |    fprintf(stderr,"ERROR: %s\n", SQ_error(sql_connection));
418  |    return(-1);
419  |  }
420  | 
421  |  if ((sql_row = SQ_row_next(sql_result)) != NULL) {
422  | /* Object exists */
423  |    sql_str = SQ_get_column_string(sql_result, sql_row, RANGE_ID);
424  |    if (sql_str != NULL) {
425  |      range_id = atol(sql_str);
426  |      free(sql_str);
427  |    }
428  |    sql_str = SQ_get_column_string(sql_result, sql_row, RANGE_START);
429  |    if (sql_str != NULL) {
430  |      prange->start = atoi(sql_str);
431  |      free(sql_str);
432  |    }
433  |    sql_str = SQ_get_column_string(sql_result, sql_row, RANGE_END);
434  |    if (sql_str != NULL) {
435  |      prange->end = atoi(sql_str);
436  |      free(sql_str);
437  |    }
438  | 
439  | /* We must process all the rows of the result */
440  | /* otherwise we'll have them as part of the next qry */      
441  |    while ( (sql_row = SQ_row_next(sql_result)) != NULL) range_id=-1;
442  |  } else 
443  |       range_id=0;  // object does not exist
444  |    
445  |  if(sql_result)SQ_free_result(sql_result);
446  |  return(range_id);
447  | }
448  | 
449  | 
450  | 
451  | 
452  | /************************************************************
453  | * long update_range()                                       *
454  | *                                                           *
455  | * Updates the range by changing the boundaries              *
456  | * Deletes the range if nothing left                         *
457  | * Merges with neighbor ranges if there is no gap between    *
458  | *                                                           *
459  | * We never update range. We create a new one with specified * 
460  | * limits and mark old one(s) for deletion, so that we can   *
461  | * make commit/rollback properly. This is possible as the    * 
462  | * primary keys are (range_id, range_start, range_end)       *
463  | *                                                           *
464  | * To finalize changes make commit/rollback                  *
465  | *                                                           *
466  | * Returns:                                                  *
467  | * >0 - returns range_id on success                          *
468  | * -1 - error (f.e. more than one object with the same PK)   *
469  | *                                                           *
470  | ************************************************************/
471  |               
472  | static long update_range(long range_id, range_t *p_newrange, SQ_connection_t *sql_connection, int commit_now)
473  | {
474  | GString *query;
475  | range_t range;
476  | long prev_range_id, next_range_id;
477  | int num;
478  | int sql_err;
479  | 
480  | /* Allocate memory */
481  |  if ((query = g_string_sized_new(STR_L)) == NULL){ 
482  |   fprintf(stderr, "E: cannot allocate gstring\n"); 
483  |   return(-1); 
484  |  }
485  | 
486  | /* Do range check */
487  |  if (( p_newrange->end > MAX_RANGE ) || ( p_newrange->start < MIN_RANGE )) return(-1);
488  | 
489  | /* Check if the range collapses */
490  |  if ( p_newrange->end < p_newrange->start ) {
491  |  /* then delete the range */  
492  |  /* Do this by marking the range for deletion for further commit/rollback */
493  |   if(commit_now)
494  |    g_string_sprintf(query, "DELETE FROM nic_hdl " 
495  |                            "WHERE range_id=%ld ",
496  |                             range_id);
497  |   else  
498  |    g_string_sprintf(query, "UPDATE nic_hdl SET thread_id=%d "
499  |                            "WHERE range_id=%ld ",
500  | 			    NH_DELETE, range_id);   
501  |       
502  | /*   fprintf(stderr, "update_range[%s]\n", query->str); */
503  |    sql_err=SQ_execute_query(sql_connection, query->str, (SQ_result_set_t **)NULL);
504  |    if(sql_err) {
505  |     /* An error occured */
506  |     g_string_free(query, TRUE);
507  |     return(-1);
508  |    }
509  |    num = SQ_get_affected_rows(sql_connection); 
510  |    /* this should not happen */
511  |    if(num==0) die;
512  |  
513  |  }
514  |  else {
515  |   /* update the range for the same space/source */
516  |   range.space=p_newrange->space;
517  |   range.source=p_newrange->source; 
518  |   /* Check if we can join with previous range of the same space */
519  |   prev_range_id=get_range(p_newrange->start-1, &range, sql_connection);
520  |   /* Check if such range exists and it is not ours (this happens when we are shrinking */
521  |   if((prev_range_id>0) && (prev_range_id!=range_id)) {
522  |    /* acquire the previous range */
523  |    /* mark it for deletion for commit/rollback */
524  |    if(commit_now)
525  |       g_string_sprintf(query, "DELETE FROM nic_hdl "
526  |                               "WHERE range_id=%ld ",
527  |                                prev_range_id);
528  |    else
529  |       g_string_sprintf(query, "UPDATE nic_hdl SET thread_id=%d "
530  |                               "WHERE range_id=%ld ",
531  | 			       NH_DELETE, prev_range_id);   
532  | 
533  | 
534  | 
535  | /*    fprintf(stderr, "update_range[%s]\n", query->str); */
536  |    sql_err=SQ_execute_query(sql_connection, query->str, (SQ_result_set_t **)NULL);
537  |    if(sql_err) {
538  |     /* An error occured */
539  |     g_string_free(query, TRUE);
540  |     return(-1);
541  |    }
542  |    num = SQ_get_affected_rows(sql_connection); 
543  |    /* this should not happen */
544  |    if(num==0) die;
545  |    
546  |    /* expand the boundaries */
547  |    p_newrange->start=range.start;
548  |   }
549  | 
550  | /* Check if we can join with next range of the same space */
551  |   next_range_id=get_range(p_newrange->end+1, &range, sql_connection);
552  |   /* Check if such range exists and it is not ours (this happens when we are shrinking) */
553  |   if((next_range_id>0) && (next_range_id!=range_id)) {
554  |    /* acquire the next range */
555  |    /* mark it for deletion for commit/rollback */
556  |    if(commit_now)
557  |      g_string_sprintf(query, "DELETE FROM nic_hdl "
558  |                              "WHERE range_id=%ld ",
559  |                               next_range_id);
560  |    else	   
561  |      g_string_sprintf(query, "UPDATE nic_hdl SET thread_id=%d "
562  |                              "WHERE range_id=%ld ",
563  | 			      NH_DELETE, next_range_id);   
564  | 
565  | 
566  | 
567  | /*   fprintf(stderr, "update_range[%s]\n", query->str); */
568  |    sql_err=SQ_execute_query(sql_connection, query->str, (SQ_result_set_t **)NULL);
569  |    if(sql_err) {
570  |     /* An error occured */
571  |     g_string_free(query, TRUE);
572  |     return(-1);
573  |    }
574  |    num = SQ_get_affected_rows(sql_connection); 
575  |    /* this should not happen */
576  |    if(num==0) die;
577  |    
578  |    /* expand the boundaries */
579  |    p_newrange->end=range.end;
580  |   }
581  |  
582  | /* Now make a larger range. Mark current for deletion and new for commit/rollback */ 
583  |   if(commit_now)
584  |    g_string_sprintf(query, "UPDATE nic_hdl "
585  |                            "SET range_start=%ld, range_end=%ld "
586  | 			   "WHERE range_id=%ld",
587  |                            p_newrange->start, p_newrange->end, range_id);
588  |   else {
589  | 
590  |    g_string_sprintf(query, "UPDATE nic_hdl SET thread_id=%d "
591  |                            "WHERE range_id=%ld ",
592  | 			   NH_DELETE, range_id);
593  | /*   fprintf(stderr, "update_range[%s]\n", query->str); */
594  |    sql_err=SQ_execute_query(sql_connection, query->str, (SQ_result_set_t **)NULL);
595  |    if(sql_err) {
596  |     /* An error occured */
597  |     g_string_free(query, TRUE);
598  |     return(-1);
599  |    }
600  |    num = SQ_get_affected_rows(sql_connection); 
601  |    /* this should not happen */
602  |    if(num==0) die;
603  |    
604  |    g_string_sprintf(query, "INSERT nic_hdl "
605  |                            "SET thread_id=%d, range_id=%ld, space='%s', source='%s', range_start=%ld, range_end=%ld ",
606  |                            NH_INSERT, range_id, p_newrange->space, p_newrange->source, p_newrange->start, p_newrange->end);  
607  |   } 
608  | 
609  | /*   fprintf(stderr, "update_range[%s]\n", query->str); */
610  |    sql_err=SQ_execute_query(sql_connection, query->str, (SQ_result_set_t **)NULL);
611  |    if(sql_err) {
612  |     /* An error occured */
613  |     g_string_free(query, TRUE);
614  |     return(-1);
615  |    }
616  |    num = SQ_get_affected_rows(sql_connection); 
617  |    /* this should not happen */
618  |    if(num==0) die;
619  |  } /* update the range */
620  | 
621  |  g_string_free(query, TRUE);
622  |  return (range_id);
623  | }
624  |                
625  | /************************************************************
626  | * long create_range()                                       *
627  | *                                                           *
628  | * Creates a new range in a given name space                 *
629  | *                                                           *
630  | * To finalize changes make commit/rollback                  *
631  | *                                                           *
632  | * Returns:                                                  *
633  | * >0 - returns range_id on success                          *
634  | * -1 - error (f.e. more than one object with the same PK)   *
635  | *                                                           *
636  | ************************************************************/
637  |                 
638  | static long create_range(range_t *p_range, SQ_connection_t *sql_connection, int commit_now)
639  | {
640  | GString *query;
641  | int sql_err, num;
642  | long range_id;
643  | 
644  |  /* Allocate memory */
645  |  if ((query = g_string_sized_new(STR_L)) == NULL){ 
646  |   fprintf(stderr, "E: cannot allocate gstring\n"); 
647  |   return(-1); 
648  |  }
649  |  
650  |  /* get the next range_id */
651  |  /* XXX we cannot use autoincrement with MyISAM tables */
652  |  /* XXX because they keep the max inserted id even if  */
653  |  /* XXX it was deleted later, thus causing gaps we don't want */
654  |  
655  |  range_id=SQ_get_max_id(sql_connection, "range_id", "nic_hdl") +1;
656  |  
657  |  if(commit_now)
658  |   g_string_sprintf(query, "INSERT nic_hdl "
659  |                           "SET thread_id=0,  range_id=%ld, space='%s', source='%s', range_start=%ld, range_end=%ld ",
660  |                            range_id, p_range->space, p_range->source, p_range->start, p_range->end);
661  |  else	 
662  |   g_string_sprintf(query, "INSERT nic_hdl "
663  |                           "SET thread_id=%d, range_id=%ld, space='%s', source='%s', range_start=%ld, range_end=%ld ",
664  |                            NH_INSERT, range_id, p_range->space, p_range->source, p_range->start, p_range->end);
665  | 
666  | /* fprintf(stderr, "create_range[%s]\n", query->str); */
667  |  sql_err=SQ_execute_query(sql_connection, query->str, (SQ_result_set_t **)NULL);
668  |  g_string_free(query, TRUE);
669  |   
670  |    if(sql_err) {
671  |     /* An error occured */
672  |     return(-1);
673  |    }
674  |    num = SQ_get_affected_rows(sql_connection); 
675  |    /* this should not happen */
676  |    if(num==0) die;
677  |  return(range_id);
678  | }
679  | 
680  | 
681  | /************************************************************
682  | * int NH_comrol()                                           *
683  | *                                                           *
684  | * Commits or rolls back changes to NHR                      *
685  | *                                                           *
686  | *                                                           *
687  | * Returns:                                                  *
688  | * >0 - success                                              *
689  | * -1 - SQL error                                            *
690  | *                                                           *
691  | ************************************************************/
692  |  
693  | int NH_comrol(SQ_connection_t *sql_connection, int thread_ins, int thread_del)
694  | {
695  | GString *query;
696  | int sql_err;
697  | 
698  |  /* Allocate memory */
699  |  if ((query = g_string_sized_new(STR_L)) == NULL){ 
700  |   fprintf(stderr, "E: cannot allocate gstring\n"); 
701  |   return(-1); 
702  |  }
703  |  
704  |   g_string_sprintf(query, "DELETE FROM nic_hdl "
705  | 			  "WHERE thread_id=%d ",
706  |                           thread_del);
707  | 
708  | /* fprintf(stderr, "create_range[%s]\n", query->str); */
709  |  sql_err=SQ_execute_query(sql_connection, query->str, (SQ_result_set_t **)NULL);
710  |  if(sql_err) {
711  |     /* An error occured */
712  |     g_string_free(query, TRUE);
713  |     fprintf(stderr,"ERROR: %s\n", SQ_error(sql_connection));
714  |     die;
715  |  }
716  | 
717  |  g_string_sprintf(query, "UPDATE nic_hdl "
718  |                          "SET thread_id=0 "
719  | 			 "WHERE thread_id=%d ",
720  |                           thread_ins);
721  | 
722  | /* fprintf(stderr, "create_range[%s]\n", query->str); */
723  |  sql_err=SQ_execute_query(sql_connection, query->str, (SQ_result_set_t **)NULL);
724  |  g_string_free(query, TRUE);
725  |   
726  |  if(sql_err) {
727  |     /* An error occured */
728  |    fprintf(stderr,"ERROR: %s\n", SQ_error(sql_connection));
729  |    die;
730  |  }
731  |  
732  |  return(1);
733  | 		
734  | }
735  | 
736  |