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