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)
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,
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) {
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,
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) {
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) {
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)
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) {
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,
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,
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,
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,
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) {
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,
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,
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,
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,
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,
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,
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,
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) {
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) {
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) {
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) {
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)
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 | }