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