1    | /***************************************
2    |   $Revision: 1.15 $
3    | 
4    | 
5    |   Sql module (sq).  This is a mysql implementation of an sql module.
6    | 
7    |   Status: NOT REVUED, NOT TESTED
8    | 
9    |   Note: this code has been heavily coupled to MySQL, and may need to be changed
10   |   (to improve performance) if a new RDBMS is used.
11   | 
12   |   ******************/ /******************
13   |   Filename            : query_instructions.c
14   |   Author              : ottrey@ripe.net
15   |   OSs Tested          : Solaris
16   |   Problems            : Moderately linked to MySQL.  Not sure which inverse
17   |                         attributes each option has.  Would like to modify this
18   |                         after re-designing the objects module.
19   |   Comments            : Not sure about the different keytypes.
20   |   ******************/ /******************
21   |   Copyright (c) 1999                              RIPE NCC
22   |  
23   |   All Rights Reserved
24   |   
25   |   Permission to use, copy, modify, and distribute this software and its
26   |   documentation for any purpose and without fee is hereby granted,
27   |   provided that the above copyright notice appear in all copies and that
28   |   both that copyright notice and this permission notice appear in
29   |   supporting documentation, and that the name of the author not be
30   |   used in advertising or publicity pertaining to distribution of the
31   |   software without specific, written prior permission.
32   |   
33   |   THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
34   |   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
35   |   AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
36   |   DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
37   |   AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
38   |   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
39   |   ***************************************/
40   | #include <stdio.h>
41   | #include "which_keytypes.h"
42   | #include "query_instructions.h"
43   | #include "mysql_driver.h"
44   | #include "attributes.h"
45   | #include "rxroutines.h"
46   | #include "stubs.h"
47   | #include "constants.h"
48   | 
49   | /*+ String sizes +*/
50   | #define STR_S   63
51   | #define STR_M   255
52   | #define STR_L   1023
53   | #define STR_XL  4095
54   | #define STR_XXL 16383
55   | 
56   | 
57   | /*+ Definition of SQL query to be made +*/
58   | struct _Instruction {
59   |   WK_Type keytype;
60   |   const char *sql_primary_query;
61   |   const char *sql_inverse_query;
62   | };
63   | 
64   | /*+ SQL query to be made for each keytype: +*/
65   | static struct _Instruction Instructions[] = {
66   |   { WK_NAME,         Q_PRI_NAME,         Q_INV_NAME },         /* A name                              */
67   |   { WK_NICHDL,       Q_PRI_NICHDL,       Q_INV_NICHDL },       /* NICHDL                              */
68   |   { WK_EMAIL,        Q_PRI_EMAIL,        Q_INV_EMAIL },        /* RFC822 e-mail address               */
69   |   { WK_MAINT,        Q_PRI_MAINT,        Q_INV_MAINT },        /* Maintainer name                     */
70   |   { WK_KEYCERT,      Q_PRI_KEYCERT,      Q_INV_KEYCERT },      /* PGPKEY (see i-d for syntax)         */
71   |   { WK_IPRANGE,      Q_PRI_IPRANGE,      Q_INV_IPRANGE },      /* IP range (*) needs modification     */
72   |   { WK_IP6RANGE,     Q_PRI_IP6RANGE,     Q_INV_IP6RANGE },     /* IPv6 range (*) needs modification   */
73   |   { WK_NETNAME,      Q_PRI_NETNAME,      Q_INV_NETNAME },      /* Network name                        */
74   |   { WK_ASNUM,        Q_PRI_ASNUM,        Q_INV_ASNUM },        /* AS number                           */
75   |   { WK_ASSETNAME,    Q_PRI_ASSETNAME,    Q_INV_ASSETNAME },    /* AS set name                         */
76   |   { WK_ROUTESETNAME, Q_PRI_ROUTESETNAME, Q_INV_ROUTESETNAME }, /* Route set name                      */
77   |   { WK_DOMNAME,      Q_PRI_DOMNAME,      Q_INV_DOMNAME },      /* Domain name                         */
78   |   { WK_HOSTNAME,     Q_PRI_HOSTNAME,     Q_INV_HOSTNAME },     /* Host name                           */
79   |   { WK_LIMERICKNAME, Q_PRI_LIMERICKNAME, Q_INV_LIMERICKNAME }, /* Limerick name                       */
80   |   NULL
81   | };
82   | 
83   | 
84   | /* log_inst_print() */
85   | /*++++++++++++++++++++++++++++++++++++++
86   |   Log the instruction.
87   | 
88   |   char *str instruction to be logged.
89   |    
90   |   More:
91   |   +html+ <PRE>
92   |   Authors:
93   |         ottrey
94   |   +html+ </PRE><DL COMPACT>
95   |   +html+ <DT>Online References:
96   |   +html+ <DD><UL>
97   |   +html+ </UL></DL>
98   | 
99   |   ++++++++++++++++++++++++++++++++++++++*/
100  | static void log_inst_print(char *str) {
101  |   FILE *logf;
102  | 
103  |   if (CO_get_instr_logging() == 1) {
104  |     if (strcmp(CO_get_instr_logfile(), "stdout") == 0) {
105  |       printf("%s", str);
106  |     }
107  |     else {
108  |       logf = fopen(CO_get_instr_logfile(), "a");
109  |       fprintf(logf, "%s", str);
110  |       fclose(logf);
111  |     }
112  |   }
113  | 
114  | } /* log_inst_print() */
115  | 
116  | /* create_name_query() */
117  | /*++++++++++++++++++++++++++++++++++++++
118  |   Create an sql query for the names table. 
119  | 
120  |   char *query_str
121  | 
122  |   const char *sql_query
123  | 
124  |   const char *keys
125  |    
126  |   More:
127  |   +html+ <PRE>
128  |   Authors:
129  |         ottrey
130  |   +html+ </PRE><DL COMPACT>
131  |   +html+ <DT>Online References:
132  |   +html+ <DD><UL>
133  |   +html+ </UL></DL>
134  | 
135  |   ++++++++++++++++++++++++++++++++++++++*/
136  | static void create_name_query(char *query_str, const char *sql_query, const char *keys) {
137  |   int i;
138  |   char *word;
139  |   char from_clause_atom[STR_XL];
140  |   char from_clause[STR_XXL];
141  |   char where_clause_atom[STR_XL];
142  |   char where_clause[STR_XXL];
143  |   char *keys_tmp;
144  | 
145  |   strcpy(from_clause, "");
146  |   strcpy(where_clause, "");
147  | 
148  |   keys_tmp = (char *)calloc(1, strlen(keys)+1);
149  |   strcpy(keys_tmp, keys);
150  | 
151  |   word = (char *)strtok(keys_tmp, " ");
152  | 
153  |   sprintf(from_clause_atom, "names N%.2d", 0);
154  |   sprintf(where_clause_atom, "N%.2d.name='%s'", 0, word);
155  | 
156  |   strcat(from_clause, from_clause_atom);
157  |   strcat(where_clause, where_clause_atom);
158  | 
159  |   for (i=1; (word=(char *)strtok(NULL, " ")) != NULL; i++) {
160  |     sprintf(from_clause_atom, ", names N%.2d", i);
161  |     sprintf(where_clause_atom, " AND N%.2d.name='%s' AND N00.pe_ro_id = N%.2d.pe_ro_id", i, word, i);
162  | 
163  |     strcat(from_clause, from_clause_atom);
164  |     strcat(where_clause, where_clause_atom);
165  | 
166  |     strcpy(from_clause_atom, "");
167  |     strcpy(where_clause_atom, "");
168  |   }
169  | 
170  |   sprintf(query_str, sql_query, from_clause, where_clause);
171  | 
172  |   /* XXX Free here */
173  |   /*
174  |   free(keys_tmp);
175  |   */
176  | 
177  | } /* create_name_query() */
178  | 
179  | /* create_query() */
180  | /*++++++++++++++++++++++++++++++++++++++
181  |   Create an sql query from the query_command and the matching keytype and the
182  |   selected inverse attributes.
183  |   Note this clears the first inv_attribute it sees, so is called sequentially
184  |   until there are no inv_attributes left.
185  | 
186  |   WK_Type keytype The matching keytype.
187  | 
188  |   const Query_command *qc The query command.
189  | 
190  |   mask_t *inv_attrs_bitmap The selected inverse attributes.
191  |    
192  |   More:
193  |   +html+ <PRE>
194  |   Authors:
195  |         ottrey
196  |   +html+ </PRE><DL COMPACT>
197  |   +html+ <DT>Online References:
198  |   +html+ <DD><UL>
199  |   +html+ </UL></DL>
200  | 
201  |   ++++++++++++++++++++++++++++++++++++++*/
202  | static char *create_query(WK_Type keytype, const Query_command *qc, mask_t *inv_attrs_bitmap) {
203  |   char query_str_buf[STR_XXL];
204  |   char query_str_buf_stage1[STR_XXL];
205  |   char query_str_buf_filter[STR_XXL];
206  |   char *query_str;
207  |   const char *sql_query;
208  |   char *str;
209  |   int inverse_query;
210  | 
211  |   if ( MA_bitcount(*inv_attrs_bitmap) == 0 ) {
212  |     sql_query = Instructions[keytype].sql_primary_query;
213  |     inverse_query = 0;
214  |   }
215  |   else {
216  |     sql_query = Instructions[keytype].sql_inverse_query;
217  |     inverse_query = 1;
218  |   }
219  | 
220  |   strcpy(query_str_buf, "");
221  |   strcpy(query_str_buf_stage1, "");
222  | 
223  |   switch ( keytype ) { 
224  |     case WK_NAME:
225  |     if (sql_query != NULL) {
226  |       if ( inverse_query == 0 ) {
227  |         create_name_query(query_str_buf, sql_query, qc->keys);
228  |         /* XXX There is no way to filter -Tpn WK_NAME in the current schema design. */
229  |       }
230  |       else {
231  |         /* Inverse name query */
232  |         if ( MA_isset(*inv_attrs_bitmap, A_AC) == 1 ) {
233  |           MA_set(inv_attrs_bitmap, A_AC, 0);
234  |           sprintf(query_str_buf_stage1, sql_query, "admin_c", "admin_c", "admin_c");
235  |           create_name_query(query_str_buf, query_str_buf_stage1, qc->keys);
236  |         }
237  |         else if ( MA_isset(*inv_attrs_bitmap, A_TC) == 1 ) {
238  |           MA_set(inv_attrs_bitmap, A_TC, 0);
239  |           sprintf(query_str_buf_stage1, sql_query, "tech_c", "tech_c", "tech_c");
240  |           create_name_query(query_str_buf, query_str_buf_stage1, qc->keys);
241  |         }
242  |         else if ( MA_isset(*inv_attrs_bitmap, A_ZC) == 1 ) {
243  |           MA_set(inv_attrs_bitmap, A_ZC, 0);
244  |           sprintf(query_str_buf_stage1, sql_query, "zone_c", "zone_c", "zone_c");
245  |           create_name_query(query_str_buf, query_str_buf_stage1, qc->keys);
246  |         }
247  |         else {
248  |           MA_clear(inv_attrs_bitmap);
249  |         }
250  |       }
251  |     }
252  |     else {
253  |       MA_clear(inv_attrs_bitmap);
254  |     }
255  | 
256  |     break;
257  | 
258  |     case WK_NICHDL:
259  |     if (sql_query != NULL) {
260  |       if ( inverse_query == 0 ) {
261  |         sprintf(query_str_buf, sql_query, qc->keys);
262  |         if (   (MA_isset(qc->object_type_bitmap, A_PN) == 1)
263  |             && (MA_isset(qc->object_type_bitmap, A_RO) == 0) ) {
264  |           strcat(query_str_buf, " AND is_person = 1");
265  |         } 
266  |         else if (   (MA_isset(qc->object_type_bitmap, A_RO) == 1)
267  |                  && (MA_isset(qc->object_type_bitmap, A_PN) == 0) ) {
268  |           strcat(query_str_buf, " AND is_person = 0");
269  |         } 
270  |       }
271  |       else {
272  |         /* Inverse NICHDL query */
273  |         if ( MA_isset(*inv_attrs_bitmap, A_AC) == 1 ) {
274  |           MA_set(inv_attrs_bitmap, A_AC, 0);
275  |           sprintf(query_str_buf, sql_query, "admin_c", "admin_c", qc->keys, "admin_c");
276  |         }
277  |         else if ( MA_isset(*inv_attrs_bitmap, A_TC) == 1 ) {
278  |           MA_set(inv_attrs_bitmap, A_TC, 0);
279  |           sprintf(query_str_buf, sql_query, "tech_c", "tech_c", qc->keys, "tech_c");
280  |         }
281  |         else if ( MA_isset(*inv_attrs_bitmap, A_ZC) == 1 ) {
282  |           MA_set(inv_attrs_bitmap, A_ZC, 0);
283  |           sprintf(query_str_buf, sql_query, "zone_c", "zone_c", qc->keys, "zone_c");
284  |         }
285  |         else {
286  |           MA_clear(inv_attrs_bitmap);
287  |         }
288  |         if (   (MA_isset(qc->object_type_bitmap, A_PN) == 1)
289  |             && (MA_isset(qc->object_type_bitmap, A_RO) == 0) ) {
290  |           /* XXX This is backwards. */
291  |           strcat(query_str_buf, " AND is_person = 0");
292  |         } 
293  |         else if (   (MA_isset(qc->object_type_bitmap, A_RO) == 1)
294  |                  && (MA_isset(qc->object_type_bitmap, A_PN) == 0) ) {
295  |           /* XXX This is backwards. */
296  |           strcat(query_str_buf, " AND is_person = 1");
297  |         } 
298  |       }
299  |     }
300  |     else {
301  |       MA_clear(inv_attrs_bitmap);
302  |     }
303  |     break;
304  | 
305  |     case WK_EMAIL:
306  |     if (sql_query != NULL) {
307  |       if ( inverse_query == 0 ) {
308  |         sprintf(query_str_buf, sql_query,  qc->keys);
309  |       }
310  |       else {
311  |         /* Inverse EMAIL query */
312  |         if ( MA_isset(*inv_attrs_bitmap, A_NY) == 1 ) {
313  |           MA_set(inv_attrs_bitmap, A_NY, 0);
314  |           sprintf(query_str_buf, sql_query, qc->keys); 
315  |         }
316  |         else {
317  |           MA_clear(inv_attrs_bitmap);
318  |         }
319  |       }
320  |     }
321  |     else {
322  |       MA_clear(inv_attrs_bitmap);
323  |     }
324  |     break;
325  | 
326  |     case WK_MAINT:
327  |     if (sql_query != NULL) {
328  |       if ( inverse_query == 0 ) {
329  |         sprintf(query_str_buf, sql_query, qc->keys);
330  |       }
331  |       else {
332  |         /* Inverse MAINT query */
333  |         if ( MA_isset(*inv_attrs_bitmap, A_MB) == 1 ) {
334  |           MA_set(inv_attrs_bitmap, A_MB, 0);
335  |           sprintf(query_str_buf, sql_query, qc->keys);
336  |         }
337  |         else {
338  |           MA_clear(inv_attrs_bitmap);
339  |         }
340  |       }
341  |     }
342  |     else {
343  |       MA_clear(inv_attrs_bitmap);
344  |     }
345  |     break;
346  | 
347  |     case WK_ASNUM:
348  |     if (sql_query != NULL) {
349  |       if ( inverse_query == 0 ) {
350  |         sprintf(query_str_buf, sql_query, qc->keys);
351  |       }
352  |       else {
353  |         /* Inverse ASNUM query */
354  |         if ( MA_isset(*inv_attrs_bitmap, A_OR) == 1 ) {
355  |           MA_set(inv_attrs_bitmap, A_OR, 0);
356  |           sprintf(query_str_buf, sql_query, qc->keys);
357  |         }
358  |         else {
359  |           MA_clear(inv_attrs_bitmap);
360  |         }
361  |       }
362  |     }
363  |     else {
364  |       MA_clear(inv_attrs_bitmap);
365  |     }
366  |     break;
367  | 
368  |     case WK_DOMNAME:
369  |     if (sql_query != NULL) {
370  |       if ( inverse_query == 0 ) {
371  |         sprintf(query_str_buf, sql_query, qc->keys);
372  |       }
373  |       else {
374  |         /* Inverse DOMNAME query */
375  |         if ( MA_isset(*inv_attrs_bitmap, A_SD) == 1 ) {
376  |           MA_set(inv_attrs_bitmap, A_OR, 0);
377  |           sprintf(query_str_buf, sql_query, qc->keys);
378  |         }
379  |         else {
380  |           MA_clear(inv_attrs_bitmap);
381  |         }
382  |       }
383  |     }
384  |     else {
385  |       MA_clear(inv_attrs_bitmap);
386  |     }
387  |     break;
388  | 
389  |     default:
390  |     if (sql_query != NULL) {
391  |       if ( inverse_query == 0 ) {
392  |         sprintf(query_str_buf, sql_query, qc->keys);
393  |       }
394  |       else {
395  |         /* No Inverse query */
396  |         MA_clear(inv_attrs_bitmap);
397  |       }
398  | 
399  |     }
400  |     else {
401  |       MA_clear(inv_attrs_bitmap);
402  |     }
403  |   } /* switch() */
404  | 
405  |   if (strcmp(query_str_buf, "") == 0) {
406  |     query_str = NULL;
407  |   }
408  |   else {
409  |     query_str = (char *)calloc(1, strlen(query_str_buf)+1);
410  |     strcpy(query_str, query_str_buf);
411  |   }
412  | 
413  |   return query_str;
414  | } /* create_query() */
415  | 
416  | /* write_results() */
417  | /*++++++++++++++++++++++++++++++++++++++
418  |   Write the results to the client socket.
419  | 
420  |   SQ_result_set_t *result The result set returned from the sql query.
421  |   
422  |   int sock The socket that the client is connected to.
423  | 
424  |   XXX NB. this is very dependendant on what rows are returned in the result!!!
425  |    
426  |   More:
427  |   +html+ <PRE>
428  |   Authors:
429  |         ottrey
430  |   +html+ </PRE><DL COMPACT>
431  |   +html+ <DT>Online References:
432  |   +html+ <DD><UL>
433  |   +html+ </UL></DL>
434  | 
435  |   ++++++++++++++++++++++++++++++++++++++*/
436  | static int write_results(SQ_result_set_t *result, int sock) {
437  |   SQ_row_t *row;
438  |   char *str;
439  |   char log_str[STR_L];
440  |   int retrieved_objects=0;
441  | 
442  |   /* Get all the results - one at a time */
443  |   if (result != NULL) {
444  |     while ( (row = SQ_row_next(result)) != NULL) {
445  |       str = SQ_get_column_string(row, 0);
446  |       if (str != NULL) {
447  |         strcpy(log_str, "");
448  |         sprintf(log_str, "Retrieved serial id = %d\n", atoi(str));
449  |         log_inst_print(log_str);
450  |       }
451  |       free(str);
452  | 
453  |       str = SQ_get_column_string(row, 2);
454  |       if (str != NULL) {
455  |         SK_puts(sock, str);
456  |         SK_puts(sock, "\n");
457  |         retrieved_objects++;
458  |       }
459  |       free(str);
460  |     }
461  |   }
462  |   
463  |   return retrieved_objects;
464  | } /* write_results() */
465  | 
466  | 
467  | /* write_objects() */
468  | /*++++++++++++++++++++++++++++++++++++++
469  |   This is linked into MySQL by the fact that MySQL doesn't have sub selects
470  |   (yet).  The queries are done in two stages.  Make some temporary tables and
471  |   insert into them.  Then use them in the next select.
472  | 
473  |   SQ_connection_t *sql_connection The connection to the database.
474  | 
475  |   char *id_table The id of the temporary table (This is a result of the hacky
476  |                   way we've tried to get MySQL to do sub-selects.)
477  |   
478  |   unsigned int recursive A recursive query.
479  | 
480  |   unsigned int sock The client socket.
481  | 
482  |   More:
483  |   +html+ <PRE>
484  |   Authors:
485  |         ottrey
486  |   +html+ </PRE><DL COMPACT>
487  |   ++++++++++++++++++++++++++++++++++++++*/
488  | static void write_objects(SQ_connection_t *sql_connection, char *id_table, unsigned int recursive, unsigned int sock) {
489  |   /* XXX This should really return a linked list of the objects */
490  | 
491  |   SQ_result_set_t *result;
492  |   int retrieved_objects=0;
493  | 
494  |   char sql_command[STR_XL];
495  |   char log_str[STR_L];
496  |     
497  |   strcpy(sql_command, "");
498  |   /* XXX These may and should change a lot. */
499  |   sprintf(sql_command, Q_OBJECTS, id_table, id_table);
500  |   result = SQ_execute_query(sql_connection, sql_command);
501  | 
502  |   retrieved_objects += write_results(result, sock);
503  | 
504  |   SQ_free_result(result);
505  | 
506  |   /* Now for recursive queries */
507  |   if (recursive == 1) {
508  |     strcpy(sql_command, "");
509  |     sprintf(sql_command, Q_REC, id_table, "admin_c", id_table, id_table);
510  |     SQ_execute_query(sql_connection, sql_command);
511  | 
512  |     strcpy(sql_command, "");
513  |     sprintf(sql_command, Q_REC, id_table, "tech_c", id_table, id_table);
514  |     SQ_execute_query(sql_connection, sql_command);
515  | 
516  |     strcpy(sql_command, "");
517  |     sprintf(sql_command, Q_REC, id_table, "zone_c", id_table, id_table);
518  |     SQ_execute_query(sql_connection, sql_command);
519  | 
520  |     /* XXX These may and should change a lot. */
521  |     strcpy(sql_command, "");
522  |     sprintf(sql_command, Q_REC_OBJECTS, id_table, id_table, id_table);
523  |     result = SQ_execute_query(sql_connection, sql_command);
524  | 
525  |     retrieved_objects += write_results(result, sock);
526  | 
527  |     SQ_free_result(result);
528  | 
529  |     /* Now drop the IDS recursive table */
530  |     strcpy(sql_command, "");
531  |     sprintf(sql_command, "DROP TABLE %s_R", id_table);
532  |     SQ_execute_query(sql_connection, sql_command);
533  |   }
534  | 
535  |   /* If nothing is retreived default to return the 0th object - I.e "not found" */
536  |   if (retrieved_objects == 0) {
537  |     result = SQ_execute_query(sql_connection, Q_NO_OBJECTS);
538  |     write_results(result, sock);
539  | 
540  |     SQ_free_result(result);
541  |   }
542  | 
543  |   /* Now drop the IDS table */
544  |   strcpy(sql_command, "");
545  |   sprintf(sql_command, "DROP TABLE %s", id_table);
546  |   SQ_execute_query(sql_connection, sql_command);
547  | 
548  |   strcpy(log_str, "");
549  |   sprintf(log_str, "%d object(s) retrieved\n\n", retrieved_objects);
550  |   log_inst_print(log_str);
551  | 
552  |   if (CO_get_accounting() == 1) {
553  |     /* XXX - later man.
554  |     account(retrieved_objects);
555  |     */
556  |     printf("account(retrieved_objects);\n");
557  |   }
558  | 
559  | } /* write_objects() */
560  | 
561  | /* insert_radix_serials() */
562  | /*++++++++++++++++++++++++++++++++++++++
563  |   Insert the radix serial numbers into a temporary table in the database.
564  | 
565  |   mask_t bitmap The bitmap of attribute to be converted.
566  |    
567  |   SQ_connection_t *sql_connection The connection to the database.
568  | 
569  |   char *id_table The id of the temporary table (This is a result of the hacky
570  |                   way we've tried to get MySQL to do sub-selects.)
571  |   
572  |   GList *datlist The list of data from the radix tree.
573  | 
574  |   XXX Hmmmmm this isn't really a good place to free things... infact it's quite nasty.  :-(
575  |   
576  |   More:
577  |   +html+ <PRE>
578  |   Authors:
579  |         ottrey
580  |   +html+ </PRE><DL COMPACT>
581  |   +html+ <DT>Online References:
582  |   +html+ <DD><UL>
583  |              <LI><A HREF="http://www.gtk.org/rdp/glib/glib-doubly-linked-lists.html">Glist</A>
584  |   +html+ </UL></DL>
585  | 
586  |   ++++++++++++++++++++++++++++++++++++++*/
587  | static void insert_radix_serials(SQ_connection_t *sql_connection, char *id_table, GList *datlist) {
588  |   GList    *qitem;
589  |   char sql_command[STR_XL];
590  |   int serial;
591  |   int i;
592  | 
593  | /*
594  |   TODO -- marek --- TODO
595  |   for( qitem = g_list_last(datlist); qitem != NULL; qitem = g_list_previous(qitem)) {
596  |  */
597  |   for( qitem = g_list_first(datlist); qitem != NULL; qitem = g_list_next(qitem)) {
598  |     rx_datcpy_t *datcpy = qitem->data;
599  | 
600  |     serial = datcpy->leafcpy.data_key;
601  | 
602  |     strcpy(sql_command, "");
603  |     sprintf(sql_command, "INSERT INTO %s values (%d)\n", id_table, serial);
604  |     SQ_execute_query(sql_connection, sql_command);
605  | 
606  |     /* XXX AAAARGH why here?!?! */
607  |     wr_free(datcpy->leafcpy.data_ptr);
608  |   }
609  | 
610  |   /* XXX Possible memory leak here. -fix above?? */
611  |   g_list_foreach(datlist, rx_free_list_element, NULL);
612  |   g_list_free(datlist);
613  | 
614  | } /* insert_radix_serials() */
615  | 
616  | /* map_qc2rx() */
617  | /*++++++++++++++++++++++++++++++++++++++
618  |   The mapping between a query_command and a radix query.
619  | 
620  |   Query_instruction *qi The Query Instruction to be created from the mapping
621  |                         of the query command.
622  | 
623  |   const Query_command *qc The query command to be mapped.
624  | 
625  |   More:
626  |   +html+ <PRE>
627  |   Authors:
628  |         ottrey
629  |   +html+ </PRE><DL COMPACT>
630  |   +html+ <DT>Online References:
631  |   +html+ <DD><UL>
632  |   +html+ </UL></DL>
633  | 
634  |   ++++++++++++++++++++++++++++++++++++++*/
635  | static int map_qc2rx(Query_instruction *qi, const Query_command *qc) {
636  |   int result=1;
637  | 
638  |   qi->rx_keys = qc->keys;
639  | 
640  |   if ( (qc->L == 0) && (qc->M == 0) && (qc->l == 0) && (qc->m == 0) ) {
641  |     qi->rx_srch_mode = RX_SRCH_EXLESS;
642  |     qi->rx_par_a = 0;
643  |   }
644  |   else if ( (qc->L == 1) && (qc->M == 0) && (qc->l == 0) && (qc->m == 0) ) {
645  |     qi->rx_srch_mode = RX_SRCH_LESS;
646  |     qi->rx_par_a = RX_ALL_DEPTHS;
647  |   }
648  |   else if ( (qc->L == 0) && (qc->M == 1) && (qc->l == 0) && (qc->m == 0) ) {
649  |     qi->rx_srch_mode = RX_SRCH_MORE;
650  |     qi->rx_par_a = RX_ALL_DEPTHS;
651  |   }
652  |   else if ( (qc->L == 0) && (qc->M == 0) && (qc->l == 1) && (qc->m == 0) ) {
653  |     qi->rx_srch_mode = RX_SRCH_LESS;
654  |     qi->rx_par_a = 1;
655  |   }
656  |   else if ( (qc->L == 0) && (qc->M == 0) && (qc->l == 0) && (qc->m == 1) ) {
657  |     qi->rx_srch_mode = RX_SRCH_MORE;
658  |     qi->rx_par_a = 1;
659  |   }
660  |   else {
661  |     result = -1;
662  |   }
663  | 
664  |   return result;
665  | 
666  | } /* map_qc2rx() */
667  | 
668  | 
669  | /* QI_execute() */
670  | /*++++++++++++++++++++++++++++++++++++++
671  |   Execute the query instructions.  This is called by a g_list_foreach
672  |   function, so each of the sources in the "database source" list can be passed
673  |   into this function.
674  | 
675  |   void *database_voidptr Pointer to the database.
676  |   
677  |   void *qis_voidptr Pointer to the query_instructions.
678  |    
679  |   More:
680  |   +html+ <PRE>
681  |   Authors:
682  |         ottrey
683  |   +html+ </PRE><DL COMPACT>
684  |   +html+ <DT>Online References:
685  |   +html+ <DD><UL>
686  |              <LI><A
687  |              HREF="http://www.gtk.org/rdp/glib/glib-singly-linked-lists.html#G-SLIST-FOREACH">g_list_foreach</A>
688  |   +html+ </UL></DL>
689  | 
690  |   ++++++++++++++++++++++++++++++++++++++*/
691  | void QI_execute(void *database_voidptr, void *qis_voidptr) {
692  |   char *database = (char *)database_voidptr;
693  |   Query_instructions *qis = (Query_instructions *)qis_voidptr;
694  |   Query_instruction **ins=NULL;
695  |   char id_table[STR_S];
696  |   char sql_command[STR_XL];
697  |   GList *datlist=NULL;
698  |   int i;
699  | 
700  |   char log_str[STR_L];
701  | 
702  |   SQ_connection_t *sql_connection=NULL;
703  | 
704  |   sql_connection = SQ_get_connection(CO_get_host(), CO_get_database_port(), database, CO_get_user(), CO_get_password() );
705  | 
706  |   if (sql_connection == NULL) {
707  |     SK_puts(qis->sock, "% WARNING: Failed to make connection to ");
708  |     SK_puts(qis->sock, database);
709  |     SK_puts(qis->sock, " database mirror.\n\n");
710  |   }
711  |   else {
712  |     strcpy(sql_command, "");
713  | 
714  |     /* XXX This is a really bad thing to do.  It should'nt _have_ to be called here.
715  |        But unfortunately it does.   -- Sigh. */
716  |     sprintf(id_table, "ID_%d", mysql_thread_id(sql_connection) );
717  | 
718  |     strcpy(sql_command, "");
719  |     sprintf(sql_command, "CREATE TABLE %s ( id int ) TYPE=HEAP", id_table);
720  |     SQ_execute_query(sql_connection, sql_command);
721  | 
722  |     if (qis->recursive == 1) {
723  |       strcpy(sql_command, "");
724  |       sprintf(sql_command, "CREATE TABLE %s_R ( id int ) TYPE=HEAP", id_table);
725  |       SQ_execute_query(sql_connection, sql_command);
726  |     }
727  | 
728  |     ins = qis->instruction;
729  |     for (i=0; ins[i] != NULL; i++) {
730  |       switch ( (ins[i])->search_type ) {
731  |         case QI_SQL:
732  |           if ( (ins[i])->query_str != NULL ) {
733  |             strcpy(sql_command, "");
734  |             sprintf(sql_command, "INSERT INTO %s %s\n", id_table, (ins[i])->query_str);
735  |             SQ_execute_query(sql_connection, sql_command);
736  |           }
737  |         break;
738  | 
739  |   /* XXX I don't like this bit much.  This is one of the bits that needs re-designing. */
740  | #define RIPE_REG 17
741  |         case QI_RADIX:
742  |           datlist = NULL;
743  |           printf("searching 'in'\n");
744  |           if ( RX_asc_search((ins[i])->rx_srch_mode, (ins[i])->rx_par_a, 0, (ins[i])->rx_keys, RIPE_REG, IP_V4, RX_FAM_IN, &datlist, RX_ANS_ALL) == RX_OK ) {
745  |             insert_radix_serials(sql_connection, id_table, datlist);
746  |           }
747  |           else {
748  |             /* Skip query */
749  |             strcpy(log_str, "");
750  |             sprintf(log_str, "rx: /* Skip in query */\n");
751  |             log_inst_print(log_str);
752  |           }
753  |           datlist = NULL;
754  |           printf("searching 'rt'\n");
755  |           if ( RX_asc_search((ins[i])->rx_srch_mode, (ins[i])->rx_par_a, 0, (ins[i])->rx_keys, RIPE_REG, IP_V4, RX_FAM_RT, &datlist, RX_ANS_ALL) == RX_OK ) {;
756  |             insert_radix_serials(sql_connection, id_table, datlist);
757  |           }
758  |           else {
759  |             /* Skip query */
760  |             strcpy(log_str, "");
761  |             sprintf(log_str, "rx: /* Skip rt query */\n");
762  |             log_inst_print(log_str);
763  |           }
764  |         break;
765  | 
766  |         case QI_RADIX_IN:
767  |           datlist = NULL;
768  |           printf("searching 'in'\n");
769  |           if ( RX_asc_search((ins[i])->rx_srch_mode, (ins[i])->rx_par_a, 0, (ins[i])->rx_keys, RIPE_REG, IP_V4, RX_FAM_IN, &datlist, RX_ANS_ALL) == RX_OK ) {
770  |             insert_radix_serials(sql_connection, id_table, datlist);
771  |           }
772  |           else {
773  |             /* Skip query */
774  |             strcpy(log_str, "");
775  |             sprintf(log_str, "rx: /* Skip in query */\n");
776  |             log_inst_print(log_str);
777  |           }
778  |         break;
779  | 
780  |         case QI_RADIX_RT:
781  |           datlist = NULL;
782  |           printf("searching 'rt'\n");
783  |           if ( RX_asc_search((ins[i])->rx_srch_mode, (ins[i])->rx_par_a, 0, (ins[i])->rx_keys, RIPE_REG, IP_V4, RX_FAM_RT, &datlist, RX_ANS_ALL) == RX_OK ) {;
784  |             insert_radix_serials(sql_connection, id_table, datlist);
785  |           }
786  |           else {
787  |             /* Skip query */
788  |             strcpy(log_str, "");
789  |             sprintf(log_str, "rx: /* Skip rt query */\n");
790  |             log_inst_print(log_str);
791  |           }
792  |         break;
793  | 
794  |         default:
795  |           strcpy(log_str, "");
796  |           sprintf(log_str, "ERROR: bad search_type\n");
797  |           log_inst_print(log_str);
798  |       } /* switch */
799  |     }
800  |     write_objects(sql_connection, id_table, qis->recursive, qis->sock);
801  |   }
802  | 
803  |   SQ_close_connection(sql_connection);
804  |   
805  | } /* QI_execute() */
806  | 
807  | /* instruction_free() */
808  | /*++++++++++++++++++++++++++++++++++++++
809  |   Free the instruction.
810  | 
811  |   Query_instruction *qi query_instruction to be freed.
812  |    
813  |   More:
814  |   +html+ <PRE>
815  |   Authors:
816  |         ottrey
817  |   +html+ </PRE><DL COMPACT>
818  |   +html+ <DT>Online References:
819  |   +html+ <DD><UL>
820  |   +html+ </UL></DL>
821  | 
822  |   ++++++++++++++++++++++++++++++++++++++*/
823  | static void instruction_free(Query_instruction *qi) {
824  |   if (qi != NULL) {
825  |     if (qi->query_str != NULL) {
826  |       free(qi->query_str);
827  |     }
828  |     free(qi);
829  |   }
830  | } /* instruction_free() */
831  | 
832  | /* QI_free() */
833  | /*++++++++++++++++++++++++++++++++++++++
834  |   Free the query_instructions.
835  | 
836  |   Query_instructions *qis Query_instructions to be freed.
837  |    
838  |   XXX This isn't working too well at the moment.
839  | 
840  |   More:
841  |   +html+ <PRE>
842  |   Authors:
843  |         ottrey
844  |   +html+ </PRE><DL COMPACT>
845  |   +html+ <DT>Online References:
846  |   +html+ <DD><UL>
847  |   +html+ </UL></DL>
848  | 
849  |   ++++++++++++++++++++++++++++++++++++++*/
850  | void QI_free(Query_instructions *qis) {
851  |   /* XXX huh!?H?
852  |   int i;
853  | 
854  |   for (i=0; qis[i] != NULL; i++) {
855  |     instruction_free(*qis[i]);
856  |   }
857  |   */
858  |   if (qis != NULL) {
859  |     free(qis);
860  |   }
861  | 
862  | } /* QI_free() */
863  | 
864  | /* QI_new() */
865  | /*++++++++++++++++++++++++++++++++++++++
866  |   Create a new set of query_instructions.
867  | 
868  |   mask_t bitmap The bitmap of attribute to be converted.
869  |    
870  |   const Query_command *qc The query_command that the instructions are created
871  |                           from.
872  | 
873  |   unsigned int sock The client socket.
874  | 
875  |   More:
876  |   +html+ <PRE>
877  |   Authors:
878  |         ottrey
879  |   +html+ </PRE><DL COMPACT>
880  |   +html+ <DT>Online References:
881  |   +html+ <DD><UL>
882  |   +html+ </UL></DL>
883  | 
884  |   ++++++++++++++++++++++++++++++++++++++*/
885  | Query_instructions *QI_new(const Query_command *qc, unsigned int sock) {
886  |   Query_instructions *qis=NULL;
887  |   Query_instruction *qi=NULL;
888  |   int i_no=0,j;
889  |   WK_Type keytype;
890  |   char *query_str;
891  |   mask_t inv_attrs_bitmap;
892  |   mask_t wk_search_rx_bitmap, wk_search_sq_bitmap;
893  | 
894  |   char log_str[STR_L];
895  | 
896  |   wk_search_rx_bitmap = MA_new(WK_SEARCH_MASK_RX);
897  |   wk_search_sq_bitmap = MA_new(WK_SEARCH_MASK_SQ);
898  | 
899  |   qis = (Query_instructions *)calloc(1, sizeof(Query_instructions));
900  |   qis->sock = sock;
901  |   qis->recursive = qc->recursive;
902  | 
903  |   for (keytype=0; keytype < WK_END; keytype++) {
904  |     /* XXX This bit is really bad; and needs work - needs redesigning. */
905  |     /* if that keytype is one of the objects in the -T list.  (NB. "NULL" implies all by default) */
906  |     switch (keytype) {
907  |     case WK_NAME:
908  |     case WK_NICHDL:
909  |       if (   (MA_isset(qc->object_type_bitmap, A_PN) != 1)
910  |           && (MA_isset(qc->object_type_bitmap, A_RO) != 1) ) {
911  |         continue;
912  |       }
913  |     break;
914  | 
915  |     case WK_EMAIL:
916  |       /* XXX Hmmmm I don't know.  Search it anyway. */
917  |       ;
918  |     break;
919  | 
920  |     case WK_MAINT:
921  |       if (MA_isset(qc->object_type_bitmap, A_MT) != 1) {
922  |         continue;
923  |       }
924  |     break;
925  | 
926  |     case WK_KEYCERT:
927  |       if (MA_isset(qc->object_type_bitmap, A_KC) != 1) {
928  |         continue;
929  |       }
930  |     break;
931  | 
932  |     case WK_IPRANGE:
933  |       /* XXX Hmmmm I don't know.  Search it anyway. */
934  |       ;
935  |     break;
936  | 
937  |     case WK_IP6RANGE:
938  |       /* XXX Hmmmm I don't know.  Search it anyway. */
939  |       ;
940  |     break;
941  | 
942  |     case WK_NETNAME:
943  |       /* XXX Hmmmm I don't know.  Search it anyway. */
944  |       ;
945  |     break;
946  | 
947  |     case WK_ASNUM:
948  |       /* XXX Hmmmm I don't know.  Search it anyway. */
949  |       ;
950  |     break;
951  | 
952  |     case WK_ASSETNAME:
953  |       /* XXX Hmmmm I don't know.  Search it anyway. */
954  |       ;
955  |     break;
956  | 
957  |     case WK_ROUTESETNAME:
958  |       /* XXX Hmmmm I don't know.  Search it anyway. */
959  |       ;
960  |     break;
961  | 
962  |     case WK_DOMNAME:
963  |       if (MA_isset(qc->object_type_bitmap, A_DN) != 1) {
964  |         continue;
965  |       }
966  |     break;
967  | 
968  |     case WK_HOSTNAME:
969  |       /* XXX Hmmmm I don't know.  Search it anyway. */
970  |       ;
971  |     break;
972  | 
973  |     case WK_LIMERICKNAME:
974  |       if (MA_isset(qc->object_type_bitmap, A_LI) != 1) {
975  |         continue;
976  |       }
977  |     break;
978  | 
979  |     default:
980  |       printf("Error: bad keytype encountered in QI_new()\n");
981  |     }
982  | 
983  |     /* If matched the keytype */
984  |     if ( MA_isset(qc->keytypes_bitmap, keytype) == 1) {
985  |       qi = (Query_instruction *)calloc(1, sizeof(Query_instruction));
986  |       /* SQL Query */
987  |       if ( MA_isset(wk_search_sq_bitmap, keytype) == 1 ) {
988  |         qi->search_type = QI_SQL;
989  | 
990  |         inv_attrs_bitmap = qc->inv_attrs_bitmap;
991  |         j=0;
992  |         do {
993  |           query_str = create_query(keytype, qc, &inv_attrs_bitmap);
994  |           if (query_str != NULL) {
995  |             qi->query_str = query_str;
996  |             qis->instruction[i_no++] = qi;
997  |           }
998  |           j++;
999  |           if (j> 7) {
1000 |             strcpy(log_str, "");
1001 |             sprintf(log_str, "ERROR Too many loops .. bailing\n");
1002 |             log_inst_print(log_str);
1003 |             break;
1004 |           }
1005 |         } while (MA_bitcount(inv_attrs_bitmap));
1006 |       }
1007 |       /* Radix Query */
1008 |       else if ( MA_isset(wk_search_rx_bitmap, keytype) == 1 ) {
1009 |         if ( MA_isset(qc->object_type_bitmap, A_IN) == 1 ) {
1010 |           qi->search_type = QI_RADIX_IN;
1011 |         }
1012 |         if ( MA_isset(qc->object_type_bitmap, A_RT) == 1 ) {
1013 |           qi->search_type = QI_RADIX_RT;
1014 |         }
1015 |         if (   ( MA_isset(qc->object_type_bitmap, A_IN) == 1 ) 
1016 |             && ( MA_isset(qc->object_type_bitmap, A_RT) == 1 ) ) {
1017 |           qi->search_type = QI_RADIX;
1018 |         }
1019 |         if (map_qc2rx(qi, qc) == 1) {
1020 |           /* Add the query_instruction to the array */
1021 |           qis->instruction[i_no++] = qi;
1022 |         }
1023 |         else {
1024 |           strcpy(log_str, "");
1025 |           sprintf(log_str, "ERROR in qc2rx mapping: bad combination of flags\n");
1026 |           log_inst_print(log_str);
1027 |         }
1028 |       }
1029 |       else {
1030 |         strcpy(log_str, "");
1031 |         sprintf(log_str, "ERROR: bad search_type\n");
1032 |         log_inst_print(log_str);
1033 |       }
1034 |     }
1035 |   }
1036 |   qis->instruction[i_no++] = NULL;
1037 | 
1038 |   return qis;
1039 | 
1040 | } /* QI_new() */