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