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