## modules/qi/query_instructions.c

/* [<][>][^][v][top][bottom][index][help] */

## FUNCTIONS

This source file includes following functions.

1. create_name_query
2. create_asblock_query
3. add_filter
4. create_query
5. fast_output
6. filter
7. write_results
8. write_objects
9. insert_radix_serials
10. write_radix_immediate
11. map_qc2rx
12. run_referral
13. add_ref_name
14. qi_collect_ids
15. qi_fetch_references
16. QI_execute
17. instruction_free
18. QI_free
19. valid_query
20. QI_new
21. QI_queries_to_string

       1 /***************************************
       2   $Revision: 1.41 $
       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 <string.h>
      42 #include <glib.h>
      43
      44 #include "which_keytypes.h"
      45 #include "query_instructions.h"
      46 #include "mysql_driver.h"
      47 #include "rp.h"
      48 #include "stubs.h"
      49 #include "constants.h"
      50 #include "memwrap.h"
      51 #include "wh_queries.h"
      52
      53 /*+ String sizes +*/
      54 #define STR_S   63
      55 #define STR_M   255
      56 #define STR_L   1023
      57 #define STR_XL  4095
      58 #define STR_XXL 16383
      59
      60 /* XXX this must be removed from here!!! a .h file must be
      61    generated from xml */
      62
      63 #include "defs.h"
      64
      65 /* create_name_query() */
      66 /*++++++++++++++++++++++++++++++++++++++
      67   Create an sql query for the names table.
      68
      69   char *query_str
      70
      71   const char *sql_query
      72
      73   const char *keys
      74
      75   More:
      76   +html+ <PRE>
      77   Authors:
      78   ottrey
      79   +html+ </PRE><DL COMPACT>
      80   +html+ <DT>Online References:
      81   +html+ <DD><UL>
      82   +html+ </UL></DL>
      83
      84   ++++++++++++++++++++++++++++++++++++++*/
      85 static void create_name_query(char *query_str, const char *sql_query, const char *keys) {
         /* [<][>][^][v][top][bottom][index][help] */
      86   int i;
      87   /* Allocate stuff */
      88   GString *from_clause = g_string_sized_new(STR_XL);
      89   GString *where_clause = g_string_sized_new(STR_XL);
      90   gchar **words = g_strsplit(keys, " ", 0);
      91
      92   /* double quotes " are used in queries to allow querying for
      93      names like O'Hara */
      94
      95   g_string_sprintfa(from_clause, "names N%.2d", 0);
      96   g_string_sprintfa(where_clause, "N%.2d.name=\"%s\"", 0, words[0]);
      97
      98   for (i=1; words[i] != NULL; i++) {
      99     g_string_sprintfa(from_clause, ", names N%.2d", i);
     100     g_string_sprintfa(where_clause, " AND N%.2d.name=\"%s\" AND N00.object_id = N%.2d.object_id", i, words[i], i);
     101   }
     102
     103   sprintf(query_str, sql_query, from_clause->str, where_clause->str);
     104
     105   /* Free up stuff */
     106   g_strfreev(words);
     107   g_string_free(where_clause,/* CONSTCOND */ TRUE);
     108   g_string_free(from_clause, /* CONSTCOND */ TRUE);
     109
     110 } /* create_name_query() */
     111
     112 /*+ create_asblock_query:
     113
     114   given a string like: AS1
     115                        AS1 - AS10
     116                        AS1-AS10
     117   construct a range query for the as_block table
     118 */
     119 static int create_asblock_query(char *query_str,
         /* [<][>][^][v][top][bottom][index][help] */
     120                                 const char *sql_query,
     121                                 const char *keys) {
     122   char *keycopy = wr_string(keys);
     123   char *token, *cursor = keycopy;
     124   int  asnums[2] = {0,0};
     125   int index = 0; /* index into the asnums array */
     126
     127
     128   while( (token = strsep( &cursor, "-" )) != NULL && index < 2) {
     129     if( sscanf(token, "AS%d", &asnums[index++]) < 1 ) {
     130       return -1; /* error */
     131     }
     132   }
     133   /* if only beginning was supplied, copy it as end */
     134   if( index == 1 ) {
     135     asnums[1] = asnums[0];
     136   }
     137
     138   /* now construct the query */
     139   sprintf(query_str, sql_query, asnums[0], asnums[1]);
     140
     141   wr_free(keycopy);
     142   return 0;
     143 }
     144
     145 static void add_filter(char *query_str, const Query_command *qc) {
         /* [<][>][^][v][top][bottom][index][help] */
     146   int i;
     147   int qlen;
     148   char filter_atom[STR_M];
     149
     150 /*
     151   if (MA_bitcount(qc->object_type_bitmap) > 0) {
     152     g_string_sprintfa(query_str, " AND (");
     153     for (i=0; i < C_END; i++) {
     154       if (MA_isset(qc->object_type_bitmap, i)) {
     155         g_string_sprintfa(query_str, "i.object_type = %d OR ", DF_get_class_dbase_code(i));
     156       }
     157     }
     158     g_string_truncate(query_str, query_str->len-3);
     159     g_string_append_c(query_str, ')');
     160   }
     161 */
     162   if (MA_bitcount(qc->object_type_bitmap) > 0) {
     163     strcat(query_str, " AND (");
     164     for (i=0; i < C_END; i++) {
     165       if (MA_isset(qc->object_type_bitmap, i)) {
     166         strcpy(filter_atom, "");
     167         sprintf(filter_atom, "i.object_type = %d OR ", i);
     168                         /* XXX class codes should be used instead:
     169                            DF_get_class_dbase_code(i))
     170                            but currently the tables contain values of enums
     171                            (C_IN, etc) and not codes
     172                         */
     173         strcat(query_str, filter_atom);
     174       }
     175     }
     176     qlen = strlen(query_str);
     177     query_str[qlen-3] = ')';
     178     query_str[qlen-2] = '\0';
     179     query_str[qlen-1] = '\0';
     180   }
     181
     182 } /* add_filter() */
     183
     184 /* create_query() */
     185 /*++++++++++++++++++++++++++++++++++++++
     186   Create an sql query from the query_command and the matching keytype and the
     187   selected inverse attributes.
     188   Note this clears the first inv_attribute it sees, so is called sequentially
     189   until there are no inv_attributes left.
     190
     191   WK_Type keytype The matching keytype.
     192
     193   const Query_command *qc The query command.
     194
     195   mask_t *inv_attrs_bitmap The selected inverse attributes.
     196
     197   More:
     198   +html+ <PRE>
     199   Authors:
     200         ottrey
     201   +html+ </PRE><DL COMPACT>
     202   +html+ <DT>Online References:
     203   +html+ <DD><UL>
     204   +html+ </UL></DL>
     205
     206   ++++++++++++++++++++++++++++++++++++++*/
     207 static char *create_query(const Query_t q, const Query_command *qc) {
         /* [<][>][^][v][top][bottom][index][help] */
     208   char *result=NULL;
     209   char result_buff[STR_XL];
     210   Q_Type_t querytype;
     211   int addquery = 0; /* controls if the query should be added to the list */
     212
     213   if (MA_bitcount(qc->inv_attrs_bitmap) > 0) {
     214     querytype = Q_INVERSE;
     215   }
     216   else {
     217     querytype = Q_LOOKUP;
     218   }
     219
     220   if ( (q.query != NULL)
     221     && (q.querytype == querytype) ) {
     222
     223     addquery = 1; /* if it got here, it should be added, unless.(see asblock)*/
     224
     225     if (q.keytype == WK_NAME) {
     226       /* Name queries require special treatment. */
     227        create_name_query(result_buff, q.query, qc->keys);
     228     }
     229     else if( q.keytype == WK_IPADDRESS ) {  /* ifaddr sql lookups */
     230         ip_range_t myrang;
     231         unsigned   begin, end;
     232         ip_keytype_t key_type;
     233
     234         if (NOERR(IP_smart_range(qc->keys, &myrang, IP_EXPN, &key_type))) {
     235             if(IP_rang_b2_space(&myrang) == IP_V4 ) {
     236                 IP_rang_b2v4(&myrang, &begin, &end);
     237                 sprintf(result_buff, q.query, begin, end);
     238             }
     239             else {
     240                 die;
     241             }
     242         }
     243     }
     244     else if( q.keytype == WK_ASRANGE ) {   /* as_block range composition */
     245       if( create_asblock_query(result_buff, q.query, qc->keys) != 0 ) {
     246         addquery = 0; /* ... unless it's not correct */
     247       }
     248     }
     249     else {
     250       sprintf(result_buff, q.query, qc->keys);
     251     }
     252
     253     if (q.class == -1 && addquery == 1 ) {
     254       /* It is class type ANY so add the object filtering */
     255       add_filter(result_buff, qc);
     256     }
     257   }
     258
     259   if( addquery == 1 ) {
     260     dieif( wr_malloc((void **)&result, strlen(result_buff)+1) != UT_OK);
     261     strcpy(result, result_buff);
     262     return result;
     263   }
     264   else {
     265     return NULL;
     266   }
     267 } /* create_query() */
     268
     269 /* fast_output() */
     270 /*++++++++++++++++++++++++++++++++++++++
     271   This is for the '-F' flag.
     272   It assumes lines starting with ' ', '\t' or '+' belong to the prior attribute.
     273
     274   Fast isn't fast anymore - it's just there for compatibility reasons.
     275   This could be speed up if there were breaks out of the loops, once it matched something.
     276   (Wanna add a goto Marek?  :-) ).
     277
     278   const char *string The string to be "fast outputed".
     279
     280   More:
     281   +html+ <PRE>
     282   Authors:
     283         ottrey
     284   +html+ </PRE><DL COMPACT>
     285   +html+ <DT>Online References:
     286   +html+ <DD><UL>
     287   +html+ </UL></DL>
     288
     289   ++++++++++++++++++++++++++++++++++++++*/
     290
     291 char *fast_output(const char *str)
         /* [<][>][^][v][top][bottom][index][help] */
     292 {
     293 int i,j;
     294 char *result;
     295 char result_bit[STR_L];
     296 char result_buff[STR_XL];
     297 gchar **lines = g_strsplit(str, "\n", 0);
     298 char * const *attribute_names;
     299 gboolean filtering_an_attribute = FALSE;
     300 char *value;
     301
     302 attribute_names = DF_get_attribute_names();
     303
     304 strcpy(result_buff, "");
     305  for (j=0; lines[j] != NULL; j++) {
     306    for(i=0; attribute_names[i] != NULL; i++) {
     307      if (strncmp(attribute_names[i], lines[j], strlen(attribute_names[i])) == 0) {
     308        strcpy(result_bit, "");
     309        /* This is the juicy bit that converts the likes of; "source: RIPE" to "*so: RIPE" */
     310        value = strchr(lines[j], ':');
     311        value++;
     312        /* Now get rid of whitespace. */
     313        while (*value == ' ' || *value == '\t') {
     314          value++;
     315        }
     316        sprintf(result_bit, "*%s: %s\n", DF_get_attribute_code(i), value);
     317        strcat(result_buff, result_bit);
     318      }
     319      /* CONSTCOND */
     320      else if (filtering_an_attribute == TRUE) {
     321        switch (lines[j][0]) {
     322        case ' ':
     323        case '\t':
     324        case '+':
     325          strcpy(result_bit, "");
     326          sprintf(result_bit, "%s\n", lines[j]);
     327          strcat(result_buff, result_bit);
     328          break;
     329
     330        default:
     331          filtering_an_attribute = FALSE;
     332        }
     333      }
     334    }
     335  }
     336
     337
     338  dieif( wr_malloc((void **)&result, strlen(result_buff)+1) != UT_OK);
     339
     340  strcpy(result, result_buff);
     341
     342  return result;
     343 } /* fast_output() */
     344
     345 /* filter() */
     346 /*++++++++++++++++++++++++++++++++++++++
     347   Basically it's for the '-K' flag for non-set (and non-radix) objects.
     348   It assumes lines starting with ' ', '\t' or '+' belong to the prior attribute.
     349
     350   This could be speed up if there were breaks out of the loops, once it matched something.
     351   (Wanna add a goto Marek?  :-) ).
     352
     353   const char *string The string to be filtered.
     354
     355   More:
     356   +html+ <PRE>
     357   Authors:
     358         ottrey
     359   +html+ </PRE><DL COMPACT>
     360   +html+ <DT>Online References:
     361   +html+ <DD><UL>
     362   +html+ </UL></DL>
     363
     364   ++++++++++++++++++++++++++++++++++++++*/
     365 char *filter(const char *str) {
         /* [<][>][^][v][top][bottom][index][help] */
     366   int i,j, passed=0;
     367   char *result;
     368   char result_bit[STR_L];
     369   char result_buff[STR_XL];
     370   gchar **lines = g_strsplit(str, "\n", 0);
     371   char * const *filter_names;
     372   gboolean filtering_an_attribute = FALSE;
     373
     374   filter_names = DF_get_filter_names();
     375
     376   strcpy(result_buff, "");
     377   for (i=0; filter_names[i] != NULL; i++) {
     378     for (j=0; lines[j] != NULL; j++) {
     379       if (strncmp(filter_names[i], lines[j], strlen(filter_names[i])) == 0) {
     380         strcpy(result_bit, "");
     381         sprintf(result_bit, "%s\n", lines[j]);
     382         strcat(result_buff, result_bit);
     383         passed++;
     384
     385         /* can someone explain where %^&()! lint sees the condition here ? */
     386         /* CONSTCOND */
     387         filtering_an_attribute = TRUE;
     388       }
     389       /* CONSTCOND */
     390       else if (filtering_an_attribute == TRUE) {
     391         switch (lines[j][0]) {
     392           case ' ':
     393           case '\t':
     394           case '+':
     395             strcpy(result_bit, "");
     396             sprintf(result_bit, "%s\n", lines[j]);
     397             strcat(result_buff, result_bit);
     398           break;
     399
     400           default:
     401             filtering_an_attribute = FALSE;
     402         }
     403       }
     404     }
     405   }
     406
     407   if(passed) {
     408     strcat(result_buff, "\n");
     409   }
     410
     411   dieif( wr_malloc((void **)&result, strlen(result_buff)+1) != UT_OK);
     412   strcpy(result, result_buff);
     413
     414   return result;
     415 } /* filter() */
     416
     417 /* write_results() */
     418 /*++++++++++++++++++++++++++++++++++++++
     419   Write the results to the client socket.
     420
     421   SQ_result_set_t *result The result set returned from the sql query.
     422   unsigned filtered       if the objects should go through a filter (-K)
     423   sk_conn_st *condat      Connection data for the client
     424   int maxobjects          max # of objects to write
     425
     426   XXX NB. this is very dependendant on what rows are returned in the result!!!
     427
     428   More:
     429   +html+ <PRE>
     430   Authors:
     431         ottrey
     432   +html+ </PRE><DL COMPACT>
     433   +html+ <DT>Online References:
     434   +html+ <DD><UL>
     435   +html+ </UL></DL>
     436
     437   ++++++++++++++++++++++++++++++++++++++*/
     438 static int write_results(SQ_result_set_t *result,
         /* [<][>][^][v][top][bottom][index][help] */
     439                          unsigned filtered,
     440                          unsigned fast,
     441                          sk_conn_st *condat,
     442                          acc_st    *acc_credit,
     443                          acl_st    *acl
     444                          ) {
     445   SQ_row_t *row;
     446   char *str;
     447   char *filtrate;
     448   char *fasted;
     449   int retrieved_objects=0;
     450   char *objt;
     451   int type;
     452
     453   /* Get all the results - one at a time */
     454   if (result != NULL) {
     455     /* here we are making use of the mysql_store_result capability
     456        of interrupting the cycle of reading rows. mysql_use_result
     457        does not allow that, must be read until end */
     458
     459       while ( (row = SQ_row_next(result)) != NULL  &&  acc_credit->denials == 0 ) {
     460           if (  (str = SQ_get_column_string(result, row, 0)) == NULL
     461              || (objt = SQ_get_column_string(result, row, 3)) == NULL )  {
     462           /* handle it somehow ? */
     463           die;
     464       }
     465       else  {
     466           /* get + add object type */
     467           type = atoi(objt);
     468
     469           /* ASP_QI_LAST_DET */
     470           ER_dbg_va(FAC_QI, ASP_QI_LAST_DET,
     471                     "Retrieved serial id = %d , type = %s", atoi(str), objt);
     472
     473           wr_free(str);
     474           wr_free(objt);
     475       }
     476
     477       /* decrement credit for accounting purposes */
     478
     479       /* XXX the definition of private/public should go into the defs (xml) */
     480       switch( type ) {
     481       case C_PN:
     482       case C_RO:
     483         if( acc_credit->private_objects <= 0 && acl->maxbonus != -1 ) {
     484           /* must be negative, will be subtracted */
     485           acc_credit->denials = -1;
     486           continue; /* go to the head of the loop */
     487         }
     488         acc_credit->private_objects --;
     489         break;
     490       default:
     491         if( acc_credit->public_objects <= 0 && acl->maxpublic != -1 ) {
     492           acc_credit->denials = -1;
     493           continue; /* go to the head of the loop */
     494         }
     495         acc_credit->public_objects --;
     496       }
     497
     498       if ((str = SQ_get_column_string(result, row, 2)) == NULL) { die; }
     499       else {
     500
     501         /* The fast output stage */
     502         if (fast == 1) {
     503           fasted = fast_output(str);
     504           wr_free(str);
     505           str = fasted;
     506         }
     507
     508         /* The filtering stage */
     509         if (filtered == 0) {
     510           SK_cd_puts(condat, str);
     511           SK_cd_puts(condat, "\n");
     512         }
     513         else {
     514
     515           /* XXX accounting should be done AFTER that, and not for objects
     516              filtered out */
     517
     518           filtrate = filter(str);
     519           SK_cd_puts(condat, filtrate);
     520           wr_free(filtrate);
     521         }
     522         retrieved_objects++;
     523       }
     524       wr_free(str);
     525     }
     526   }
     527
     528   return retrieved_objects;
     529 } /* write_results() */
     530
     531 /* write_objects() */
     532 /*++++++++++++++++++++++++++++++++++++++
     533   This is linked into MySQL by the fact that MySQL doesn't have sub selects
     534   (yet).  The queries are done in two stages.  Make some temporary tables and
     535   insert into them.  Then use them in the next select.
     536
     537   SQ_connection_t *sql_connection The connection to the database.
     538
     539   char *id_table The id of the temporary table (This is a result of the hacky
     540                   way we've tried to get MySQL to do sub-selects.)
     541
     542   sk_conn_st *condat  Connection data for the client
     543
     544   More:
     545   +html+ <PRE>
     546   Authors:
     547         ottrey
     548   +html+ </PRE><DL COMPACT>
     549   ++++++++++++++++++++++++++++++++++++++*/
     550 static void write_objects(SQ_connection_t *sql_connection,
         /* [<][>][^][v][top][bottom][index][help] */
     551                           char *id_table,
     552                           unsigned int filtered,
     553                           unsigned int fast,
     554                           sk_conn_st *condat,
     555                           acc_st    *acc_credit,
     556                           acl_st    *acl
     557                           )
     558 {
     559   /* XXX This should really return a linked list of the objects */
     560
     561   SQ_result_set_t *result, *order_res;
     562   SQ_row_t *order_row;
     563   int retrieved_objects=0;
     564   char sql_command[STR_XL];
     565
     566 #if 0
     567   SQ_execute_query( sql_connection, "SELECT object_type FROM object_order ORDER BY order_code", &order_res );
     568   while( (order_row = SQ_row_next(order_res)) != NULL ) {
     569     char *object_type = SQ_get_column_string(order_res, order_row, 0);
     570     sprintf(sql_command, Q_OBJECTS, id_table, object_type);
     571
     572     exec/write
     573   }
     574   SQ_free_result(order_res);
     575 #endif
     576
     577   sprintf(sql_command, Q_OBJECTS, id_table);
     578
     579   dieif(SQ_execute_query(sql_connection, sql_command, &result) == -1 );
     580
     581   retrieved_objects = write_results(result, filtered, fast, condat,
     582                                     acc_credit, acl);
     583   SQ_free_result(result);
     584
     585 } /* write_objects() */
     586
     587 /* insert_radix_serials() */
     588 /*++++++++++++++++++++++++++++++++++++++
     589   Insert the radix serial numbers into a temporary table in the database.
     590
     591   mask_t bitmap The bitmap of attribute to be converted.
     592
     593   SQ_connection_t *sql_connection The connection to the database.
     594
     595   char *id_table The id of the temporary table (This is a result of the hacky
     596                   way we've tried to get MySQL to do sub-selects.)
     597
     598   GList *datlist The list of data from the radix tree.
     599
     600   XXX Hmmmmm this isn't really a good place to free things... infact it's quite nasty.  :-(
     601
     602   More:
     603   +html+ <PRE>
     604   Authors:
     605         ottrey
     606   +html+ </PRE><DL COMPACT>
     607   +html+ <DT>Online References:
     608   +html+ <DD><UL>
     609              <LI><A HREF="http://www.gtk.org/rdp/glib/glib-doubly-linked-lists.html">Glist</A>
     610   +html+ </UL></DL>
     611
     612   ++++++++++++++++++++++++++++++++++++++*/
     613 static void insert_radix_serials(SQ_connection_t *sql_connection, char *id_table, GList *datlist) {
         /* [<][>][^][v][top][bottom][index][help] */
     614   GList    *qitem;
     615   char sql_command[STR_XL];
     616   int serial;
     617
     618   for( qitem = g_list_first(datlist); qitem != NULL; qitem = g_list_next(qitem)) {
     619     rx_datcpy_t *datcpy = qitem->data;
     620
     621     serial = datcpy->leafcpy.data_key;
     622
     623     sprintf(sql_command, "INSERT INTO %s values (%d)", id_table, serial);
     624     dieif(SQ_execute_query(sql_connection, sql_command, NULL) == -1);
     625
     626     wr_free(datcpy->leafcpy.data_ptr);
     627   }
     628
     629   wr_clear_list( &datlist );
     630
     631 } /* insert_radix_serials() */
     632
     633
     634 /* write_radix_immediate() */
     635 /*++++++++++++++++++++++++++++++++++++++
     636   Display the immediate data carried with the objects returned by the
     637   radix tree.
     638
     639   GList *datlist      The linked list of dataleaf copies
     640   sk_conn_st *condat  Connection data for the client
     641   acc_st  *acc_credit Accounting struct
     642
     643 More:
     644   +html+ <PRE>
     645   Authors:
     646         marek
     647   +html+ </PRE><DL COMPACT>
     648   +html+ <DT>Online References:
     649   +html+ <DD><UL>
     650   +html+ </UL></DL>
     651
     652
     653   Also free the list of answers.
     654 */
     655 static void write_radix_immediate(GList *datlist,
         /* [<][>][^][v][top][bottom][index][help] */
     656                                   sk_conn_st *condat,
     657                                   acc_st    *acc_credit)
     658 {
     659   GList    *qitem;
     660
     661   for( qitem = g_list_first(datlist); qitem != NULL; qitem = g_list_next(qitem)) {
     662     rx_datcpy_t *datcpy = qitem->data;
     663
     664     SK_cd_puts(condat, datcpy->leafcpy.data_ptr );
     665     SK_cd_puts(condat, "\n");
     666
     667     wr_free(datcpy->leafcpy.data_ptr);
     668
     669     acc_credit->public_objects --;
     670   }
     671
     672   wr_clear_list( &datlist );
     673 } /* write_radix_immediate() */
     674
     675
     676 /* map_qc2rx() */
     677 /*++++++++++++++++++++++++++++++++++++++
     678   The mapping between a query_command and a radix query.
     679
     680   Query_instruction *qi The Query Instruction to be created from the mapping
     681                         of the query command.
     682
     683   const Query_command *qc The query command to be mapped.
     684
     685   More:
     686   +html+ <PRE>
     687   Authors:
     688         ottrey
     689   +html+ </PRE><DL COMPACT>
     690   +html+ <DT>Online References:
     691   +html+ <DD><UL>
     692   +html+ </UL></DL>
     693
     694   ++++++++++++++++++++++++++++++++++++++*/
     695 static int map_qc2rx(Query_instruction *qi, const Query_command *qc) {
         /* [<][>][^][v][top][bottom][index][help] */
     696   int result=1;
     697
     698   qi->rx_keys = qc->keys;
     699
     700   if ( (qc->L == 0) && (qc->M == 0) && (qc->l == 0) && (qc->m == 0) && (qc->x == 0) ) {
     701     qi->rx_srch_mode = RX_SRCH_EXLESS;
     702       qi->rx_par_a = 0;
     703   }
     704   else if ( (qc->L == 1) && (qc->M == 0) && (qc->l == 0) && (qc->m == 0) && (qc->x == 0) ) {
     705     qi->rx_srch_mode = RX_SRCH_LESS;
     706     qi->rx_par_a = RX_ALL_DEPTHS;
     707   }
     708   else if ( (qc->L == 0) && (qc->M == 1) && (qc->l == 0) && (qc->m == 0) && (qc->x == 0) ) {
     709     qi->rx_srch_mode = RX_SRCH_MORE;
     710       qi->rx_par_a = RX_ALL_DEPTHS;
     711   }
     712   else if ( (qc->L == 0) && (qc->M == 0) && (qc->l == 1) && (qc->m == 0) && (qc->x == 0) ) {
     713     qi->rx_srch_mode = RX_SRCH_LESS;
     714     qi->rx_par_a = 1;
     715   }
     716   else if ( (qc->L == 0) && (qc->M == 0) && (qc->l == 0) && (qc->m == 1) && (qc->x == 0) ) {
     717     qi->rx_srch_mode = RX_SRCH_MORE;
     718     qi->rx_par_a = 1;
     719   }
     720   else if ( (qc->L == 0) && (qc->M == 0) && (qc->l == 0) && (qc->m == 0) && (qc->x == 1) ) {
     721     qi->rx_srch_mode = RX_SRCH_EXACT;
     722     qi->rx_par_a = 0;
     723   }
     724   else {
     725       /* user error  ( XXX : this should have been checked before) */
     726
     727       ER_dbg_va(FAC_QI, ASP_QI_SKIP,
     728                 "ERROR in qc2rx mapping: bad combination of flags");
     729       result = 0;
     730   }
     731
     732   return result;
     733
     734 } /* map_qc2rx() */
     735
     736 /* run_referral() */
     737 /*
     738    invoked when no such domain found. Goes through the domain table
     739    and searches for shorter domains, then if it finds one with referral
     740    it performs it, otherwise it just returns nothing.
     741
     742    to perform referral, it actually composes the referral query
     743    for a given host/port/type and calls the whois query function.
     744
     745    Well, it returns nothing anyway (void). It just prints to the socket.
     746
     747 */
     748 void run_referral(SQ_connection_t *sql_connection,
         /* [<][>][^][v][top][bottom][index][help] */
     749                   Query_instructions *qis,
     750                   Query_environ *qe,
     751                   int qi_index) {
     752   char *dot = qis->qc->keys;
     753   char querystr[STR_L];
     754   SQ_row_t *row;
     755   SQ_result_set_t *result;
     756   char sql_command[STR_XL];
     757   int stop_loop=0;
     758   char *ref_host;
     759   char *ref_type;
     760   char *ref_port;
     761   int  ref_port_int;
     762
     763   strcpy(querystr,"");
     764
     765   while( !stop_loop && (dot=index(dot,'.')) != NULL ) {
     766     dot++;
     767
     768     ER_dbg_va(FAC_QI, ASP_QI_REF_DET, "run_referral: checking %s", dot);
     769
     770     sprintf(sql_command, "SELECT domain.object_id, domain, type, port, host FROM domain, refer WHERE domain.object_id = refer.object_id AND domain = '%s'", dot);
     771     dieif( SQ_execute_query(sql_connection, sql_command, &result) == -1);
     772
     773     switch( SQ_num_rows(result) ) {
     774       case 0: /* no such domain -> no action, will try next chunk */
     775       break;
     776
     777       case 1: /* check for referral host and perform query if present
     778                in any case end the loop */
     779       stop_loop=1;
     780       assert( (row = SQ_row_next(result)) != NULL);
     781
     782       ref_host = SQ_get_column_string(result, row, 4);
     783
     784       ER_dbg_va(FAC_QI, ASP_QI_REF_GEN, "referral host is %s", ref_host);
     785
     786       if( ref_host != NULL && strlen(ref_host) > 0 ) {
     787         ref_type = SQ_get_column_string(result, row, 2);
     788         ref_port = SQ_get_column_string(result, row, 3);
     789
     790         /* get the integer value, it should be correct */
     791         if( sscanf( ref_port, "%d",&ref_port_int) < 1 ) {
     792           die;
     793         }
     794
     795         /* compose the query: */
     796
     797         /* put -r if the reftype is RIPE and -r or -i were used */
     798         if( strcmp(ref_type,"RIPE") == 0
     799             && (   Query[qis->instruction[qi_index]->queryindex]
     800                    .querytype == Q_INVERSE
     801                    || qis->recursive > 0  )   ) {
     802           strcat(querystr," -r ");
     803         }
     804
     805         /* prepend with -Vversion,IP for type CLIENTADDRESS */
     806         if( strcmp(ref_type,"CLIENTADDRESS") == 0 ) {
     807           char optv[STR_M];
     808
     809           snprintf(optv,STR_M," -V%s,%s ","RIP0.88", qe->condat.ip);
     810           strcat(querystr,optv);
     811         }
     812
     813         /* now set the search term - set to the stripped down version
     814            for inverse query, full-length otherwise */
     815         if( Query[qis->instruction[qi_index]->queryindex].querytype == Q_INVERSE ) {
     816           strcat(querystr,dot);
     817         }
     818         else {
     819           strcat(querystr,qis->qc->keys);
     820         }
     821
     822         SK_cd_puts(&(qe->condat), "% Please note: this information is not stored in the RIPE database\n%\n% connecting to the remote referral site ");
     823         SK_cd_puts(&(qe->condat), ref_host);
     824         SK_cd_puts(&(qe->condat), "\n\n");
     825
     826         /* WH_sock(sock, host, port, query, maxlines, timeout)) */
     827         switch( WH_sock(qe->condat.sock, ref_host, ref_port_int, querystr,  25, 5) ) {
     828         case WH_TIMEOUT:
     829             SK_cd_puts(&(qe->condat),"referral timeout\n");
     830             break;
     831
     832         case WH_MAXLINES:
     833             SK_cd_puts(&(qe->condat),"referral maxlines exceeded\n");
     834             break;
     835
     836         case WH_BADHOST:
     837             SK_cd_puts(&(qe->condat),"referral host not found\n");
     838             break;
     839
     840         case WH_CONNECT:
     841             SK_cd_puts(&(qe->condat),"referral host not responding\n");
     842             break;
     843
     844         case WH_BIND:
     845         case WH_SOCKET:
     846             /* XXX internal server problem... what to do - wait ? */
     847         default:
     848           ;
     849         } /*switch WH_sock */
     850       }
     851       break;
     852
     853       default: /* more than one domain in this file: something broken */
     854       die;
     855     }
     856     SQ_free_result(result);
     857   }
     858 } /*run_referral*/
     859
     860 static
     861 void
     862 add_ref_name(SQ_connection_t *sql_connection,
         /* [<][>][^][v][top][bottom][index][help] */
     863              char *rectable,
     864              char *allnames
     865              )
     866 {
     867   /* construct the query, allow zero-length list */
     868   if( strlen(allnames) > 0 ) {
     869     char final_query[STR_XL];
     870     char select_query[STR_XL];
     871
     872     create_name_query(select_query, "SELECT N00.object_id FROM %s WHERE %s "
     873                       "AND N00.object_type != 100 AND N00.thread_id = 0",
     874                       allnames);
     875
     876     sprintf(final_query, "INSERT INTO %s %s",
     877             rectable,
     878             select_query);
     879
     880     dieif(SQ_execute_query(sql_connection, final_query, NULL) == -1 );
     881
     882     allnames[0]=0;
     883   }
     884 }
     885
     886 static
     887 void
     888 qi_collect_ids(SQ_connection_t *sql_connection,
         /* [<][>][^][v][top][bottom][index][help] */
     889                Query_instructions *qis,
     890                Query_environ *qe,
     891                char *id_table,
     892                GList **datlist,
     893                acc_st *acc_credit
     894                )
     895 {
     896   Query_instruction **ins=NULL;
     897   int i;
     898   int   count, errors=0;
     899   char sql_command[STR_XL];
     900   er_ret_t err;
     901   char sub_table[32];
     902
     903   sprintf(sub_table, "%s_S ", id_table);
     904
     905   /* see if there was a leftover table from a crashed session
     906    * (assume the ID cannot be currently in use)
     907    */
     908   sprintf(sql_command, "DROP TABLE IF EXISTS %s", sub_table);
     909   dieif( SQ_execute_query(sql_connection, sql_command, NULL) == -1 );
     910
     911   /* create a table for special subqueries (domain only for now) */
     912   sprintf(sql_command, "CREATE TABLE %s ( id int ) TYPE=HEAP", sub_table);
     913   dieif( SQ_execute_query(sql_connection, sql_command, NULL) == -1 );
     914
     915   /* Iterate through query instructions */
     916   ins = qis->instruction;
     917   for (i=0; ins[i] != NULL && errors == 0; i++) {
     918     Query_instruction *qi = ins[i];
     919
     920     switch ( qi->search_type ) {
     921     case R_SQL:
     922       if ( qi->query_str != NULL ) {
     923
     924         /* handle special cases first */
     925         if( Query[qi->queryindex].class == C_DN ) {
     926
     927           /* XXX if any more cases than just domain appear, we will be
     928              cleaning the _S table from the previous query here
     929
     930              "DELETE FROM %s_S"
     931           */
     932
     933           /* now query into the _S table */
     934           sprintf(sql_command, "INSERT INTO %s%s", sub_table, qi->query_str);
     935           dieif( SQ_execute_query(sql_connection, sql_command, NULL) == -1);
     936
     937           /* if any results - copy to the id's table.
     938              Otherwise, run referral */
     939           count = SQ_get_affected_rows(sql_connection);
     940
     941           ER_dbg_va(FAC_QI, ASP_QI_COLL_DET,
     942                     "DN lookup for %s found %d entries", qis->qc->keys, count);
     943
     944           if( count ) {
     945             sprintf(sql_command, "INSERT INTO %s SELECT id FROM %s",
     946                     id_table, sub_table);
     947             dieif(SQ_execute_query(sql_connection, sql_command, NULL) == -1);
     948           }
     949
     950           if( count == 0
     951               || Query[qi->queryindex].querytype == Q_INVERSE ) {
     952             /* now: if the domain was not found, we run referral.
     953                unless prohibited by a flag
     954
     955                But for inverse queries we return the things that were
     956                or were not found AND also do the referral unless prohibited.
     957             */
     958             if (qis->qc->R == 0) {
     959               run_referral(sql_connection, qis, qe, i);
     960             }
     961           }
     962
     963         } /* if class DN */
     964         else {
     965           sprintf(sql_command, "INSERT INTO %s %s", id_table, qi->query_str);
     966           if(SQ_execute_query(sql_connection, sql_command, NULL) == -1 ) {
     967             ER_perror(FAC_QI, QI_SQLERR," query='%s' [%d] %s",
     968                       sql_command,
     969                       SQ_errno(sql_connection), SQ_error(sql_connection));
     970             errors++;
     971           }
     972           count = SQ_get_affected_rows(sql_connection);
     973         } /* not DN */
     974       } /* if SQL query not NULL */
     975
     976       ER_dbg_va(FAC_QI, ASP_QI_COLL_DET,
     977                 "%d entries added in %s query for %s",
     978                 count, Query[qi->queryindex].descr, qis->qc->keys
     979                 );
     980       break;
     981
     982 #define RIPE_REG 17
     983     case R_RADIX:
     984
     985       if( ! qis->qc->S ) /* XXX patch: use new search algorithm by default */ {
     986         err = RP_new_asc_search(qi->rx_srch_mode, qi->rx_par_a, 0,
     987                             qi->rx_keys, RIPE_REG,
     988                             Query[qi->queryindex].attribute,
     989                             datlist, RX_ANS_ALL);
     990
     991       }
     992       else {
     993         err = RP_asc_search(qi->rx_srch_mode, qi->rx_par_a, 0,
     994                             qi->rx_keys, RIPE_REG,
     995                             Query[qi->queryindex].attribute,
     996                             datlist, RX_ANS_ALL);
     997       }
     998
     999       if( NOERR(err)) {
    1000         if( ER_is_traced(FAC_QI, ASP_QI_COLL_DET ) ) {
    1001           /* prevent unnecessary g_list_length call */
    1002
    1003           ER_dbg_va(FAC_QI, ASP_QI_COLL_DET,
    1004                     "%d entries after %s (mode %d par %d reg %d) query for %s",
    1005                     g_list_length(*datlist),
    1006                     Query[qi->queryindex].descr,
    1007                     qi->rx_srch_mode, qi->rx_par_a,
    1008                     RIPE_REG,
    1009                     qi->rx_keys);
    1010         }
    1011       }
    1012       else {
    1013         ER_inf_va(FAC_QI, ASP_QI_COLL_DET,
    1014                   "RP_asc_search returned %x ", err);
    1015       }
    1016       break;
    1017
    1018     default: die;
    1019     } /* switch */
    1020   } /* for <every instruction> */
    1021
    1022   /* Now drop the _S table */
    1023   sprintf(sql_command, "DROP TABLE %s", sub_table);
    1024   dieif(SQ_execute_query(sql_connection, sql_command, NULL) == -1 );
    1025
    1026 }
    1027
    1028 static
    1029 void
    1030 qi_fetch_references(SQ_connection_t *sql_connection,
         /* [<][>][^][v][top][bottom][index][help] */
    1031                     char *id_table,
    1032                     acc_st *acc_credit
    1033                     )
    1034 {
    1035 char rec_table[32];
    1036     SQ_result_set_t *result;
    1037     SQ_row_t *row;
    1038     int thisid = 0;
    1039     int oldid = 0;
    1040     char allnames[STR_M];
    1041     char sql_command[STR_XL];
    1042
    1043     sprintf(rec_table, "%s_R", id_table);
    1044
    1045     /* see if there was a leftover table from a crashed session
    1046      * (assume the ID cannot be currently in use)
    1047      */
    1048     sprintf(sql_command, "DROP TABLE IF EXISTS %s ", rec_table);
    1049     dieif( SQ_execute_query(sql_connection, sql_command, NULL) == -1 );
    1050
    1051     /* a temporary table for recursive data must be created, because
    1052        a query using the same table as a source and target is illegal
    1053        ( like: INSERT into ID_123 SELECT * FROM ID_123,admin_c WHERE ... )
    1054     */
    1055     sprintf(sql_command, "CREATE TABLE %s ( id int PRIMARY KEY NOT NULL ) TYPE=HEAP", rec_table);
    1056     dieif(SQ_execute_query(sql_connection, sql_command, NULL) == -1 );
    1057
    1058     /* find the contacts */
    1059     sprintf(sql_command, Q_REC, rec_table, id_table, "author");
    1060     dieif(SQ_execute_query(sql_connection, sql_command, NULL) == -1 );
    1061
    1062     sprintf(sql_command, Q_REC, rec_table, id_table, "admin_c");
    1063     dieif(SQ_execute_query(sql_connection, sql_command, NULL) == -1 );
    1064
    1065     sprintf(sql_command, Q_REC, rec_table, id_table, "tech_c" );
    1066     dieif(SQ_execute_query(sql_connection, sql_command, NULL) == -1 );
    1067
    1068     sprintf(sql_command, Q_REC, rec_table, id_table, "zone_c" );
    1069     dieif(SQ_execute_query(sql_connection, sql_command, NULL) == -1 );
    1070
    1071
    1072     /* replace references to dummies by references by name */
    1073     sprintf(sql_command,
    1074             " SELECT id, name    FROM %s IDS STRAIGHT_JOIN names "
    1075             " WHERE IDS.id = names.object_id "
    1076             "      AND names.object_type = 100"
    1077             " ORDER BY id",
    1078             rec_table);
    1079
    1080     dieif(SQ_execute_query(sql_connection, sql_command, &result) == -1 );
    1081
    1082     allnames[0]=0;
    1083     /* now go through the results and collect names */
    1084     while ( (row = SQ_row_next(result)) != NULL ) {
    1085       char *id   = SQ_get_column_string(result, row, 0);
    1086       char *name = SQ_get_column_string(result, row, 1);
    1087
    1088       thisid = atoi(id);
    1089
    1090       /* when the id changes, the name is complete */
    1091       if( thisid != oldid && oldid != 0 ) {
    1092         add_ref_name( sql_connection, rec_table, allnames);
    1093       }
    1094
    1095       strcat(allnames, name);
    1096       strcat(allnames, " ");
    1097       oldid = thisid;
    1098       wr_free(id);
    1099       wr_free(name);
    1100     }
    1101     /* also do the last name */
    1102     add_ref_name( sql_connection, rec_table, allnames);
    1103
    1104     SQ_free_result(result);
    1105
    1106     /* now copy things back to the main temporary table   */
    1107     sprintf(sql_command, "INSERT INTO %s SELECT * FROM %s",
    1108             id_table, rec_table);
    1109     dieif(SQ_execute_query(sql_connection, sql_command, NULL) == -1 );
    1110
    1111     /* Now drop the IDS recursive table */
    1112     sprintf(sql_command, "DROP TABLE %s", rec_table);
    1113     dieif(SQ_execute_query(sql_connection, sql_command, NULL) == -1 );
    1114 }
    1115
    1116
    1117 /* QI_execute() */
    1118 /*++++++++++++++++++++++++++++++++++++++
    1119   Execute the query instructions.  This is called for each source.
    1120
    1121   void *database_voidptr Pointer to the database.
    1122
    1123   void *qis_voidptr Pointer to the query_instructions.
    1124
    1125   More:
    1126   +html+ <PRE>
    1127   Authors:
    1128         ottrey
    1129   +html+ </PRE>
    1130   ++++++++++++++++++++++++++++++++++++++*/
    1131 er_ret_t QI_execute(void *database_voidptr,
         /* [<][>][^][v][top][bottom][index][help] */
    1132                     Query_instructions *qis,
    1133                     Query_environ *qe,
    1134                     acc_st *acc_credit,
    1135                     acl_st *acl
    1136                     )
    1137 {
    1138   char *database = (char *)database_voidptr;
    1139   Query_instruction **ins=NULL;
    1140   char id_table[STR_S];
    1141   char sql_command[STR_XL];
    1142   GList *datlist=NULL;
    1143   int i;
    1144   SQ_connection_t *sql_connection=NULL;
    1145   int   count, errors=0;
    1146   er_ret_t err;
    1147
    1148   sql_connection = SQ_get_connection(CO_get_host(), CO_get_database_port(),
    1149                                      database,
    1150                                      CO_get_user(), CO_get_password() );
    1151
    1152   if (sql_connection == NULL) {
    1153     ER_perror(FAC_QI, QI_CANTDB," database='%s' [%d] %s",
    1154               database, SQ_errno(sql_connection), SQ_error(sql_connection));
    1155     return QI_CANTDB;
    1156   }
    1157
    1158   sprintf(id_table, "ID_%ld", mysql_thread_id(sql_connection) );
    1159
    1160   /* see if there was a leftover table from a crashed session
    1161    * (assume the ID cannot be currently in use)
    1162    */
    1163   sprintf(sql_command, "DROP TABLE IF EXISTS %s ", id_table);
    1164   dieif( SQ_execute_query(sql_connection, sql_command, NULL) == -1 );
    1165
    1166   /* create a table for id's of all objects found NOT NULL , UNIQUE(id) */
    1167   sprintf(sql_command, "CREATE TABLE %s ( id int PRIMARY KEY NOT NULL ) TYPE=HEAP", id_table);
    1168   dieif( SQ_execute_query(sql_connection, sql_command, NULL) == -1 );
    1169
    1170   qi_collect_ids(sql_connection, qis, qe, id_table, &datlist, acc_credit);
    1171
    1172   /* post-processing */
    1173   if( qis->filtered == 0 ) {
    1174     /* add radix results (only if -K is not active) */
    1175     insert_radix_serials(sql_connection, id_table, datlist);
    1176   }
    1177
    1178   /* fetch recursive objects (ac,tc,zc,ah) */
    1179   if ( qis->recursive ) {
    1180     qi_fetch_references(sql_connection, id_table, acc_credit);
    1181   } /* if recursive */
    1182
    1183   /* display */
    1184   /* -K filtering:
    1185    * right now only filtering, no expanding sets like write_set_objects()
    1186    */
    1187
    1188   /* display the immediate data from the radix tree */
    1189   if( qis->filtered == 1 ) {
    1190     write_radix_immediate(datlist, &(qe->condat), acc_credit );
    1191   }
    1192
    1193   /* display objects from the IDs table */
    1194   write_objects(sql_connection, id_table, qis->filtered,
    1195                 qis->fast, &(qe->condat), acc_credit, acl);
    1196
    1197   /* Now drop the IDS table */
    1198   sprintf(sql_command, "DROP TABLE %s", id_table);
    1199   dieif(SQ_execute_query(sql_connection, sql_command, NULL) == -1 );
    1200   SQ_close_connection(sql_connection);
    1201 } /* QI_execute() */
    1202
    1203
    1204
    1205 /* instruction_free() */
    1206 /*++++++++++++++++++++++++++++++++++++++
    1207   Free the instruction.
    1208
    1209   Query_instruction *qi query_instruction to be freed.
    1210
    1211   More:
    1212   +html+ <PRE>
    1213   Authors:
    1214         ottrey
    1215   +html+ </PRE>
    1216   ++++++++++++++++++++++++++++++++++++++*/
    1217 static void instruction_free(Query_instruction *qi) {
         /* [<][>][^][v][top][bottom][index][help] */
    1218   if (qi != NULL) {
    1219     if (qi->query_str != NULL) {
    1220       wr_free(qi->query_str);
    1221     }
    1222     wr_free(qi);
    1223   }
    1224 } /* instruction_free() */
    1225
    1226 /* QI_free() */
    1227 /*++++++++++++++++++++++++++++++++++++++
    1228   Free the query_instructions.
    1229
    1230   Query_instructions *qis Query_instructions to be freed.
    1231
    1232   XXX This isn't working too well at the moment.
    1233
    1234   More:
    1235   +html+ <PRE>
    1236   Authors:
    1237         ottrey
    1238   +html+ </PRE>
    1239   ++++++++++++++++++++++++++++++++++++++*/
    1240 void QI_free(Query_instructions *qis) {
         /* [<][>][^][v][top][bottom][index][help] */
    1241   int i;
    1242
    1243   for (i=0; qis->instruction[i] != NULL; i++) {
    1244     instruction_free(qis->instruction[i]);
    1245   }
    1246
    1247   if (qis != NULL) {
    1248     wr_free(qis);
    1249   }
    1250
    1251 } /* QI_free() */
    1252
    1253 /*++++++++++++++++++++++++++++++++++++++
    1254   Determine if this query should be conducted or not.
    1255
    1256   If it was an inverse query - it the attribute appears in the query command's bitmap.
    1257   If it was a lookup query - if the attribute appears in the object type bitmap or
    1258                              disregard if there is no object_type bitmap (Ie object filter).
    1259
    1260   mask_t bitmap The bitmap of attribute to be converted.
    1261
    1262   const Query_command *qc The query_command that the instructions are created
    1263                           from.
    1264
    1265   const Query_t q The query being investigated.
    1266
    1267   ++++++++++++++++++++++++++++++++++++++*/
    1268 static int valid_query(const Query_command *qc, const Query_t q) {
         /* [<][>][^][v][top][bottom][index][help] */
    1269   int result=0;
    1270
    1271   if (MA_isset(qc->keytypes_bitmap, q.keytype) == 1) {
    1272     if (q.query != NULL) {
    1273       switch (q.querytype) {
    1274         case Q_INVERSE:
    1275           if (MA_isset(qc->inv_attrs_bitmap, q.attribute) ) {
    1276             result = 1;
    1277           }
    1278         break;
    1279
    1280         case Q_LOOKUP:
    1281           if (MA_bitcount(qc->object_type_bitmap) == 0) {
    1282             result=1;
    1283           }
    1284           else if (q.class<0 || MA_isset(qc->object_type_bitmap, q.class)) {
    1285             result=1;
    1286           }
    1287         break;
    1288
    1289         default:
    1290           fprintf(stderr, "qi:valid_query() -> Bad querytype\n");
    1291       }
    1292     }
    1293   }
    1294
    1295   return result;
    1296 } /* valid_query() */
    1297
    1298 /* QI_new() */
    1299 /*++++++++++++++++++++++++++++++++++++++
    1300   Create a new set of query_instructions.
    1301
    1302   const Query_command *qc The query_command that the instructions are created
    1303                           from.
    1304
    1305   const Query_environ *qe The environmental variables that they query is being
    1306                           performed under.
    1307   More:
    1308   +html+ <PRE>
    1309   Authors:
    1310         ottrey
    1311   +html+ </PRE>
    1312   ++++++++++++++++++++++++++++++++++++++*/
    1313 Query_instructions *QI_new(const Query_command *qc, const Query_environ *qe) {
         /* [<][>][^][v][top][bottom][index][help] */
    1314   Query_instructions *qis=NULL;
    1315   Query_instruction *qi=NULL;
    1316   int i_no=0;
    1317   int i;
    1318   char *query_str;
    1319
    1320   dieif(wr_calloc( (void **) & qis, 1, sizeof(Query_instructions)) != UT_OK);
    1321
    1322   qis->filtered = qc->filtered;
    1323   qis->fast = qc->fast;
    1324   qis->recursive = qc->recursive;
    1325   qis->qc = (qc);
    1326
    1327
    1328   for (i=0; Query[i].query != NULL; i++) {
    1329
    1330     /* If a valid query. */
    1331     if ( valid_query(qc, Query[i]) == 1) {
    1332
    1333       dieif( wr_calloc((void **) &qi, 1, sizeof(Query_instruction)) != UT_OK);
    1334
    1335       qi->queryindex = i;
    1336
    1337       /* SQL Query */
    1338       if ( Query[i].refer == R_SQL) {
    1339         qi->search_type = R_SQL;
    1340         query_str = create_query(Query[i], qc);
    1341
    1342         if (query_str!= NULL) {
    1343           qi->query_str = query_str;
    1344           qis->instruction[i_no++] = qi;
    1345         }
    1346       }
    1347       /* Radix Query */
    1348       else if (Query[i].refer == R_RADIX) {
    1349         qi->search_type = R_RADIX;
    1350
    1351         if (map_qc2rx(qi, qc) == 1) {
    1352           int j;
    1353           int found=0;
    1354
    1355           /* check that there is no such query yet, for example if
    1356              more than one keytype (wk) matched */
    1357           for (j=0; j<i_no; j++) {
    1358             Query_instruction *qij = qis->instruction[j];
    1359
    1360             if(    qij->search_type == R_RADIX
    1361                    && Query[qij->queryindex].attribute
    1362                    == Query[qi ->queryindex].attribute) {
    1363
    1364               found=1;
    1365               break;
    1366             }
    1367           }
    1368
    1369           if ( found ) {
    1370             /* Discard the Query Instruction */
    1371             wr_free(qi);
    1372           }
    1373           else {
    1374             /* Add the query_instruction to the array */
    1375             qis->instruction[i_no++] = qi;
    1376           }
    1377         }
    1378       }
    1379       else {
    1380           /* ERROR: bad search_type */
    1381           die;
    1382       }
    1383     }
    1384   }
    1385   qis->instruction[i_no++] = NULL;
    1386
    1387
    1388   {  /* tracing */
    1389       char *descrstr = QI_queries_to_string(qis);
    1390
    1391       ER_dbg_va(FAC_QI, ASP_QI_COLL_GEN, "Queries: %s", descrstr );
    1392       wr_free( descrstr );
    1393   }
    1394
    1395   return qis;
    1396
    1397 } /* QI_new() */
    1398
    1399 /* QI_queries_to_string()
    1400
    1401    returns a list of descriptions for queries that will be performed.
    1402 */
    1403
    1404 char *QI_queries_to_string(Query_instructions *qis)
         /* [<][>][^][v][top][bottom][index][help] */
    1405 {
    1406    Query_instruction *qi;
    1407    int i;
    1408    char *resstr = NULL;
    1409
    1410    dieif( wr_realloc((void **)&resstr, resstr, 2 ) != UT_OK);
    1411    strcpy(resstr, "{");
    1412
    1413    for( i = 0; ( qi=qis->instruction[i] ) != NULL;  i++ ) {
    1414        char *descr = Query[qi->queryindex].descr;
    1415        int oldres = strlen( resstr );
    1416
    1417        dieif( wr_realloc((void **)&resstr, resstr, oldres+strlen(descr)+2) != UT_OK);
    1418        strcat(resstr, descr);
    1419        strcat(resstr, ",");
    1420    }
    1421    if( i>0 ) {
    1422        /* cancel the last comma */
    1423        resstr[strlen(resstr)-1] = 0;
    1424    }
    1425
    1426    dieif( wr_realloc((void **)&resstr, resstr, strlen( resstr ) + 2 )
    1427           != UT_OK);
    1428    strcat(resstr, "}");
    1429
    1430    return resstr;
    1431 }

/* [<][>][^][v][top][bottom][index][help] */