1 | /***************************************
2 | $Revision: 1.42 $
3 |
4 | SQL module (sq) - this is a MySQL implementation of the SQL module.
5 |
6 | Status: NOT REVUED, TESTED
7 |
8 | ******************/ /******************
9 | Filename : mysql_driver.c
10 | Authors : ottrey@ripe.net
11 | marek@ripe.net
12 | OSs Tested : Solaris 7 / sun4u / sparc
13 | ******************/ /******************
14 | Copyright (c) 1999,2000,2001,2002 RIPE NCC
15 |
16 | All Rights Reserved
17 |
18 | Permission to use, copy, modify, and distribute this software and its
19 | documentation for any purpose and without fee is hereby granted,
20 | provided that the above copyright notice appear in all copies and that
21 | both that copyright notice and this permission notice appear in
22 | supporting documentation, and that the name of the author not be
23 | used in advertising or publicity pertaining to distribution of the
24 | software without specific, written prior permission.
25 |
26 | THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
27 | ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
28 | AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
29 | DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
30 | AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
31 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
32 | ***************************************/
33 |
34 | #include "rip.h"
35 |
36 | #include <stdlib.h>
37 | #include <stdio.h>
38 | #include <time.h>
39 | #include <sys/timeb.h>
40 | #include <strings.h>
41 | #include <sys/types.h>
42 | #include <limits.h>
43 | #include <errno.h>
44 | #include <glib.h>
45 |
46 | /*
47 | Description:
48 |
49 | Connect to the the MySQL database, returning an error if unsuccessful.
50 |
51 | Arguments:
52 |
53 | SQ_connection_t **conn; used to return pointer to connection structure
54 |
55 | const char *host; database server host to connect to, may be NULL or
56 | "localhost", in which case Unix sockets may be used
57 |
58 | unsigned int port; port to connect to database server on, may be 0 to use
59 | default
60 |
61 | const char *db; name of database to use, may be NULL
62 |
63 | const char *user; name of user to connect as, if NULL then the current Unix
64 | user login is used
65 |
66 | const char *password; password to send, may be NULL to not use a password
67 |
68 | Returns:
69 |
70 | SQ_OK on success
71 |
72 | SQ_CTCONN on error; the exact reason may be determined by using SQ_error()
73 | on the value returned in *conn - this structure should be properly via
74 | SQ_close_connection(), even on error
75 |
76 | Notes:
77 |
78 | Most parameters are passed straight through to the MySQL connect function,
79 | so the MySQL documentation should be checked for current meaning.
80 | */
81 |
82 | er_ret_t
83 | SQ_try_connection (SQ_connection_t **conn, const char *host,
84 | unsigned int port, const char *db,
85 | const char *user, const char *password)
86 | {
87 | SQ_connection_t *res;
88 |
89 | *conn = mysql_init(NULL);
90 | dieif(*conn == NULL); /* XXX SK - need to call "out of memory handler" */
91 |
92 | mysql_options(*conn, MYSQL_READ_DEFAULT_GROUP, "client");
93 |
94 | res = mysql_real_connect(*conn, host, user, password, db, port, NULL, 0);
95 | if (res == NULL) {
96 | return SQ_CTCONN;
97 | } else {
98 | return SQ_OK;
99 | }
100 | }
101 |
102 | /* SQ_get_connection() */
103 | /*++++++++++++++++++++++++++++++++++++++
104 | Get a connection to the database.
105 |
106 | const char *host
107 |
108 | unsigned int port
109 |
110 | const char *db
111 |
112 | const char *user
113 |
114 | const char *password
115 |
116 | More:
117 | +html+ <PRE>
118 | Authors:
119 | ottrey
120 | +html+ </PRE><DL COMPACT>
121 | +html+ <DT>Online References:
122 | +html+ <DD><UL>
123 | +html+ <LI><A HREF="http://www.tcx.se/Manual/manual.html#mysql_init">mysql_init()</A>
124 | +html+ <LI><A HREF="http://www.tcx.se/Manual/manual.html#mysql_real_connect">mysql_real_connect()</A>
125 | +html+ </UL></DL>
126 |
127 | ++++++++++++++++++++++++++++++++++++++*/
128 | SQ_connection_t *SQ_get_connection(const char *host, unsigned int port, const char *db, const char *user, const char *password) {
129 |
130 | SQ_connection_t *sql_connection;
131 | er_ret_t res;
132 | unsigned try = 0;
133 |
134 | /* XXX MB.
135 | This is really kludgy!
136 | For some (unknown yet) reason, sometimes the connection does not
137 | work the first time. So we try up to 3 times here, and give up only
138 | then.
139 |
140 | Check the logfiles for warnings, especially with newer mysql version,
141 | like 3.23. The problem may or may not go away.
142 |
143 | SK - I added a sleep() to avoid crushing the poor server.
144 | */
145 |
146 | for (;;) {
147 | /* try to connect */
148 | res = SQ_try_connection(&sql_connection, host, port, db, user, password);
149 |
150 | /* on success, return our result */
151 | if (NOERR(res)) {
152 | return sql_connection;
153 | }
154 | else {
155 |
156 | /* if we've tried enough, exit with error */
157 | if (try >= 3) {
158 | ER_perror(FAC_SQ, SQ_CTCONN, " %s; %s", db,
159 | sql_connection ? SQ_error(sql_connection) : "-?");
160 | die;
161 | }
162 |
163 | /* otherwise, prepare to try again */
164 | ER_perror(FAC_SQ, SQ_CNCT, " %s; %s", db,
165 | sql_connection ? SQ_error(sql_connection) : "-?");
166 |
167 | if (try > 0) {
168 | sleep(try);
169 | }
170 | try++;
171 |
172 | if( sql_connection ) {
173 | SQ_close_connection(sql_connection);
174 | }
175 | }
176 | }/* for(;;) */
177 | } /* SQ_get_connection() */
178 |
179 | /* SQ_execute_query() */
180 | /*++++++++++++++++++++++++++++++++++++++
181 | Execute the sql query.
182 |
183 | SQ_connection_t *sql_connection Connection to database.
184 |
185 | const char *query SQL query.
186 |
187 | SQ_result_set_t *result ptr to the structure to hold result.
188 | May be NULL if no result is needed.
189 |
190 | Returns:
191 | 0 if the query was successful.
192 | Non-zero if an error occured.
193 |
194 | More:
195 | +html+ <PRE>
196 | Authors:
197 | ottrey, andrei, marek
198 | +html+ </PRE><DL COMPACT>
199 | +html+ <DT>Online References:
200 | +html+ <DD><UL>
201 | +html+ <LI><A HREF="http://www.tcx.se/Manual/manual.html#mysql_query">mysql_query()</A>
202 | +html+ <LI><A HREF="http://www.tcx.se/Manual/manual.html#mysql_use_result">mysql_use_result()</A>
203 | +html+ </UL></DL>
204 |
205 | ++++++++++++++++++++++++++++++++++++++*/
206 | int SQ_execute_query(SQ_connection_t *sql_connection,
207 | const char *query, SQ_result_set_t **result_ptr)
208 | {
209 | int err;
210 | SQ_result_set_t *result;
211 |
212 | ut_timer_t start_time, stop_time;
213 |
214 | UT_timeget(&start_time);
215 |
216 | err = mysql_query(sql_connection, query);
217 |
218 | /* log the time and result of the query */
219 | if (err == 0) {
220 | result = mysql_store_result(sql_connection);
221 |
222 | if (ER_is_traced(FAC_SQ, ASP_SQ_QRYTIME)) {
223 | float seconds;
224 |
225 | UT_timeget(&stop_time);
226 | seconds = UT_timediff( &start_time, &stop_time );
227 |
228 | ER_dbg_va(FAC_SQ, ASP_SQ_QRYTIME,
229 | "spent %.2f sec; got %d rows from [%s: %s]",
230 | seconds,
231 | SQ_get_affected_rows(sql_connection),
232 | sql_connection->db,
233 | query);
234 | }
235 |
236 | if(result_ptr) *result_ptr=result;
237 | else if(result) mysql_free_result(result);
238 | return(0);
239 | }
240 | else return(-1);
241 |
242 | } /* SQ_execute_query() */
243 |
244 | /*
245 | Description:
246 |
247 | Performs identially to SQ_execute_query(), except that it does not read the
248 | entire query into memory.
249 |
250 | Notes:
251 |
252 | No data may be written to the table until the entire result set is read,
253 | so this should only be used in cases where:
254 |
255 | 1. an unacceptably large amount of memory will be returned by the query
256 | 2. there is no chance that a user can accidentally or maliciously
257 | prevent the result set from being read in a expedicious manner
258 | */
259 |
260 | int
261 | SQ_execute_query_nostore(SQ_connection_t *sql_connection,
262 | const char *query, SQ_result_set_t **result_ptr)
263 | {
264 | int err;
265 | SQ_result_set_t *result;
266 |
267 | err = mysql_query(sql_connection, query);
268 | if (err != 0) {
269 | return -1;
270 | }
271 | result = mysql_use_result(sql_connection);
272 | if (result == NULL) {
273 | return -1;
274 | }
275 | *result_ptr = result;
276 | return 0;
277 | } /* SQ_execute_query_nostore() */
278 |
279 | /* SQ_get_column_count() */
280 | /*++++++++++++++++++++++++++++++++++++++
281 | Get the column count.
282 |
283 | SQ_result_set_t *result The results from the query.
284 |
285 | More:
286 | +html+ <PRE>
287 | Authors:
288 | ottrey
289 | +html+ </PRE><DL COMPACT>
290 | +html+ <DT>Online References:
291 | +html+ <DD><UL>
292 | +html+ <LI><A HREF="http://www.tcx.se/Manual/manual.html#mysql_num_fields">mysql_num_fields()</A>
293 | +html+ </UL></DL>
294 |
295 | ++++++++++++++++++++++++++++++++++++++*/
296 | int SQ_get_column_count(SQ_result_set_t *result) {
297 | int cols;
298 |
299 | cols = mysql_num_fields(result);
300 |
301 | return cols;
302 |
303 | } /* SQ_get_column_count() */
304 |
305 | /* SQ_get_table_size() */
306 | /*++++++++++++++++++++++++++++++++++++++
307 | Get the row count of a table
308 |
309 | char *table The table to be examined
310 |
311 | More:
312 | +html+ <PRE>
313 | Authors:
314 | marek
315 | +html+ </PRE>
316 |
317 | ++++++++++++++++++++++++++++++++++++++*/
318 | int SQ_get_table_size(SQ_connection_t *sql_connection,
319 | char *table) {
320 | int count;
321 | GString *sql_command;
322 | SQ_result_set_t *result;
323 | SQ_row_t *row;
324 | char *countstr;
325 |
326 | sql_command = g_string_new("");
327 | g_string_sprintf(sql_command, "SELECT COUNT(*) FROM %s", table);
328 | dieif(SQ_execute_query(sql_connection, sql_command->str, &result) == -1 );
329 | g_string_free(sql_command, TRUE);
330 |
331 | row = SQ_row_next(result);
332 |
333 | countstr = SQ_get_column_string(result, row, 0);
334 | sscanf(countstr, "%d", &count);
335 | UT_free(countstr);
336 |
337 | SQ_free_result(result);
338 |
339 | return count;
340 | } /* SQ_get_table_size() */
341 |
342 | /* SQ_get_affected_rows() */
343 | /*++++++++++++++++++++++++++++++++++++++
344 | Get the row count of a table
345 |
346 | char *table The table to be examined
347 |
348 | More:
349 | +html+ <PRE>
350 | Authors:
351 | marek
352 | +html+ </PRE>
353 |
354 | ++++++++++++++++++++++++++++++++++++++*/
355 | int SQ_get_affected_rows(SQ_connection_t *sql_connection)
356 | {
357 | return (int)mysql_affected_rows(sql_connection);
358 | }/* SQ_get_affected_rows() */
359 |
360 | /* SQ_get_insert_id() */
361 | /*++++++++++++++++++++++++++++++++++++++
362 | Get the ID that was most recently generated for an AUTO_INCREMENT field
363 |
364 |
365 | More:
366 | +html+ <PRE>
367 | Authors:
368 | andrei
369 | +html+ </PRE>
370 |
371 | ++++++++++++++++++++++++++++++++++++++*/
372 | long SQ_get_insert_id(SQ_connection_t *sql_connection)
373 | {
374 | return (long)mysql_insert_id(sql_connection);
375 | }/* SQ_get_insert_id() */
376 |
377 | /* SQ_get_column_label() */
378 | /*++++++++++++++++++++++++++++++++++++++
379 | Get the column label.
380 |
381 | SQ_result_set_t *result The results from the query.
382 |
383 | unsigned int column The column index.
384 |
385 | More:
386 | +html+ <PRE>
387 | Authors:
388 | ottrey
389 | +html+ </PRE><DL COMPACT>
390 | +html+ <DT>Online References:
391 | +html+ <DD><UL>
392 | +html+ <LI><A HREF="http://www.tcx.se/Manual/manual.html#mysql_fetch_field_direct">mysql_fetch_field_direct()</A>
393 | +html+ </UL></DL>
394 |
395 | ++++++++++++++++++++++++++++++++++++++*/
396 | char *SQ_get_column_label(SQ_result_set_t *result, unsigned int column) {
397 | char *str;
398 | /* MySQL decided to change their interface. Doh! */
399 | #ifdef OLDMYSQL
400 | MYSQL_FIELD field;
401 |
402 | field = mysql_fetch_field_direct(result, column);
403 |
404 | str = UT_strdup(field.name);
405 | #else
406 | MYSQL_FIELD *field;
407 |
408 | field = mysql_fetch_field_direct(result, column);
409 |
410 | str = UT_strdup(field->name);
411 | #endif
412 |
413 | /*
414 | printf("column=%d\n", column);
415 | printf("field.name=%s\n", field.name);
416 | printf("field.table=%s\n", field.table);
417 |
418 | printf("field.def=%s\n", field.def);
419 |
420 | printf("field.type=%d\n", field.type);
421 | printf("field.length=%d\n", field.length);
422 | printf("field.max_length=%d\n", field.max_length);
423 | printf("field.flags=%d\n", field.flags);
424 | printf("field.decimals=%d\n", field.decimals);
425 | */
426 |
427 | return str;
428 |
429 | } /* SQ_get_column_label() */
430 |
431 | /* SQ_get_column_max_length() */
432 | /*++++++++++++++++++++++++++++++++++++++
433 | Get the max length of the column.
434 |
435 | SQ_result_set_t *result The results from the query.
436 |
437 | unsigned int column The column index.
438 |
439 | More:
440 | +html+ <PRE>
441 | Authors:
442 | ottrey
443 | +html+ </PRE><DL COMPACT>
444 | +html+ <DT>Online References:
445 | +html+ <DD><UL>
446 | +html+ <LI><A HREF="http://www.tcx.se/Manual/manual.html#mysql_fetch_field_direct">mysql_fetch_field_direct()</A>
447 | +html+ </UL></DL>
448 |
449 | ++++++++++++++++++++++++++++++++++++++*/
450 | unsigned int SQ_get_column_max_length(SQ_result_set_t *result, unsigned int column) {
451 | /* MySQL decided to change their interface. Doh! */
452 | #ifdef OLDMYSQL
453 | MYSQL_FIELD field;
454 |
455 | field = mysql_fetch_field_direct(result, column);
456 |
457 | return field.length;
458 | #else
459 | MYSQL_FIELD *field;
460 |
461 | field = mysql_fetch_field_direct(result, column);
462 |
463 | return field->length;
464 | #endif
465 |
466 | } /* SQ_get_column_max_length() */
467 |
468 | /* SQ_row_next() */
469 | /*++++++++++++++++++++++++++++++++++++++
470 | Get the next row.
471 |
472 | SQ_result_set_t *result The results from the query.
473 |
474 | unsigned int column The column index.
475 |
476 | More:
477 | +html+ <PRE>
478 | Authors:
479 | ottrey
480 | +html+ </PRE><DL COMPACT>
481 | +html+ <DT>Online References:
482 | +html+ <DD><UL>
483 | +html+ <LI><A HREF="http://www.tcx.se/Manual/manual.html#mysql_fetch_row">mysql_fetch_row()</A>
484 | +html+ </UL></DL>
485 |
486 | ++++++++++++++++++++++++++++++++++++++*/
487 | SQ_row_t *SQ_row_next(SQ_result_set_t *result) {
488 |
489 | return (SQ_row_t *)mysql_fetch_row(result);
490 |
491 | } /* SQ_row_next() */
492 |
493 | /* SQ_get_column_string() */
494 | /*++++++++++++++++++++++++++++++++++++++
495 | Get the column string.
496 |
497 | SQ_row_t *current_row The current row (obtained from a SQ_row_next() ).
498 |
499 | unsigned int column The column index.
500 |
501 | More:
502 | +html+ <PRE>
503 | Authors:
504 | ottrey
505 | +html+ </PRE><DL COMPACT>
506 | +html+ <DT>Online References:
507 | +html+ <DD><UL>
508 | +html+ </UL></DL>
509 |
510 | ++++++++++++++++++++++++++++++++++++++*/
511 | char *SQ_get_column_string(SQ_result_set_t *result, SQ_row_t *current_row, unsigned int column) {
512 | char *str=NULL;
513 | unsigned length = mysql_fetch_lengths(result)[column];
514 |
515 | if (current_row != NULL && current_row[column] != NULL) {
516 | str = (char *)UT_malloc(length + 1);
517 | memcpy(str, current_row[column], length );
518 | str[length] = '\0';
519 | }
520 |
521 | return str;
522 |
523 | } /* SQ_get_column_string() */
524 |
525 | /* SQ_get_column_string_nocopy - return pointer to the column string
526 | without making a copy of it */
527 | char *SQ_get_column_string_nocopy(SQ_result_set_t *result,
528 | SQ_row_t *current_row,
529 | unsigned int column)
530 | {
531 | if (current_row != NULL && current_row[column] != NULL) {
532 | return (char *)current_row[column];
533 | }
534 | return NULL;
535 | }/* SQ_get_column_string_nocopy */
536 |
537 |
538 |
539 | /* SQ_get_column_strings() */
540 | /*++++++++++++++++++++++++++++++++++++++
541 | Get the all the strings in one column.
542 |
543 | SQ_result_set_t *result The results.
544 |
545 | unsigned int column The column index.
546 |
547 | More:
548 | +html+ <PRE>
549 | Authors:
550 | ottrey
551 | +html+ </PRE><DL COMPACT>
552 | +html+ <DT>Online References:
553 | +html+ <DD><UL>
554 | +html+ </UL></DL>
555 |
556 | ++++++++++++++++++++++++++++++++++++++*/
557 | char *SQ_get_column_strings(SQ_result_set_t *result, unsigned int column) {
558 | MYSQL_ROW row;
559 | GString *buf;
560 | char *str;
561 |
562 | /* allocate a buffer for building the result in */
563 | buf = g_string_sized_new(STR_XXL);
564 |
565 | /* add each row of the result as a line to our result buffer */
566 | while ((row = mysql_fetch_row(result)) != NULL) {
567 | if (row[column] != NULL) {
568 | g_string_append(buf, row[column]);
569 | g_string_append_c(buf, '\n');
570 | }
571 | }
572 |
573 | /* if something found, copy to a string for return */
574 | if (buf->len > 0) {
575 | str = UT_strdup(buf->str);
576 | } else {
577 | str = NULL;
578 | }
579 |
580 | /* free temporary memory */
581 | g_string_free(buf, TRUE);
582 |
583 | return str;
584 |
585 | } /* SQ_get_column_strings() */
586 |
587 | /* SQ_get_column_int() */
588 | /*++++++++++++++++++++++++++++++++++++++
589 | Get an integer from the column.
590 |
591 | SQ_result_set_t *result The results.
592 |
593 | SQ_row_t *current_row The current row.
594 |
595 | unsigned int column The column index.
596 |
597 | long *resultptr pointer where the result should be stored
598 |
599 | returns -1 if error occurs, 0 otherwise.
600 | Note - it never says what error occured....
601 |
602 | More:
603 | +html+ <PRE>
604 | Authors:
605 | ottrey
606 | +html+ </PRE><DL COMPACT>
607 | +html+ <DT>Online References:
608 | +html+ <DD><UL>
609 | +html+ </UL></DL>
610 |
611 | ++++++++++++++++++++++++++++++++++++++*/
612 | int SQ_get_column_int(SQ_result_set_t *result, SQ_row_t *current_row, unsigned int column, long *resultptr) {
613 | int ret_val;
614 | long col_val;
615 | char *endptr;
616 |
617 | if (current_row[column] != NULL) {
618 | col_val = strtol((char *)current_row[column], &endptr, 10);
619 |
620 | /* under- or over-flow */
621 | if (((col_val==LONG_MIN) || (col_val==LONG_MAX)) && (errno==ERANGE)) {
622 | ret_val = -1;
623 |
624 | /* unrecognized characters in string */
625 | } else if (*endptr != '\0') {
626 | ret_val = -1;
627 |
628 | /* good parse */
629 | } else {
630 | *resultptr = col_val;
631 | ret_val = 0;
632 | }
633 | } else {
634 | ret_val = -1;
635 | }
636 | return ret_val;
637 |
638 | } /* SQ_get_column_int() */
639 |
640 |
641 | /* SQ_result_to_string() */
642 | /*++++++++++++++++++++++++++++++++++++++
643 | Convert the result set to a string.
644 |
645 | SQ_result_set_t *result The results.
646 |
647 | More:
648 | +html+ <PRE>
649 | Authors:
650 | ottrey
651 | +html+ </PRE><DL COMPACT>
652 | +html+ <DT>Online References:
653 | +html+ <DD><UL>
654 | +html+ </UL></DL>
655 |
656 | ++++++++++++++++++++++++++++++++++++++*/
657 | char *SQ_result_to_string(SQ_result_set_t *result) {
658 | MYSQL_ROW row;
659 | unsigned int no_cols;
660 | unsigned int i, j;
661 | char str_buffer[STR_XXL];
662 | char str_buffer_tmp[STR_L];
663 | char border[STR_L];
664 |
665 | char *label;
666 |
667 | unsigned int length[STR_S];
668 |
669 | strcpy(str_buffer, "");
670 |
671 | no_cols = mysql_num_fields(result);
672 |
673 | /* Determine the maximum column widths */
674 | /* XXX Surely MySQL should keep note of this for me! */
675 | strcpy(border, "");
676 | for (i=0; i < no_cols; i++) {
677 | length[i] = SQ_get_column_max_length(result, i);
678 | /* Make sure the lenghts don't get too long */
679 | if (length[i] > STR_M) {
680 | length[i] = STR_M;
681 | }
682 | strcat(border, "*");
683 | for (j=0; (j <= length[i]) && (j < STR_L); j++) {
684 | strcat(border, "-");
685 | }
686 | }
687 | strcat(border, "*\n");
688 | /*
689 | for (i=0; i < no_cols; i++) {
690 | printf("length[%d]=%d\n", i, length[i]);
691 | }
692 | */
693 |
694 | strcat(str_buffer, border);
695 |
696 | for (i=0; i < no_cols; i++) {
697 | label = SQ_get_column_label(result, i);
698 | if (label != NULL) {
699 | sprintf(str_buffer_tmp, "| %-*s", length[i], label);
700 | strcat(str_buffer, str_buffer_tmp);
701 | }
702 | }
703 | strcat(str_buffer, "|\n");
704 |
705 | strcat(str_buffer, border);
706 |
707 |
708 | while ((row = mysql_fetch_row(result)) != NULL) {
709 | for (i=0; i < no_cols; i++) {
710 | if (row[i] != NULL) {
711 | sprintf(str_buffer_tmp, "| %-*s", length[i], row[i]);
712 | }
713 | else {
714 | sprintf(str_buffer_tmp, "| %-*s", length[i], "NuLL");
715 | }
716 | strcat(str_buffer, str_buffer_tmp);
717 | }
718 | strcat(str_buffer, "|\n");
719 |
720 | if (strlen(str_buffer) >= (STR_XXL - STR_XL) ) {
721 | strcat(str_buffer, "And some more stuff...\n");
722 | break;
723 | }
724 | }
725 |
726 | strcat(str_buffer, border);
727 |
728 | return UT_strdup(str_buffer);
729 |
730 | } /* SQ_result_to_string() */
731 |
732 | /* SQ_free_result() */
733 | /*++++++++++++++++++++++++++++++++++++++
734 | Free the result set.
735 |
736 | SQ_result_set_t *result The results.
737 |
738 | More:
739 | +html+ <PRE>
740 | Authors:
741 | ottrey
742 | +html+ </PRE><DL COMPACT>
743 | +html+ <DT>Online References:
744 | +html+ <DD><UL>
745 | +html+ <LI><A HREF="http://www.tcx.se/Manual/manual.html#mysql_free_result">mysql_free_result()</A>
746 | +html+ </UL></DL>
747 |
748 | ++++++++++++++++++++++++++++++++++++++*/
749 | void SQ_free_result(SQ_result_set_t *result) {
750 | mysql_free_result(result);
751 | } /* SQ_free_result() */
752 |
753 |
754 | /* SQ_close_connection() */
755 | /*++++++++++++++++++++++++++++++++++++++
756 | Call this function to close a connection to the server
757 |
758 | SQ_connection_t *sql_connection The connection to the database.
759 |
760 | More:
761 | +html+ <PRE>
762 | Authors:
763 | ottrey
764 | +html+ </PRE><DL COMPACT>
765 | +html+ <DT>Online References:
766 | +html+ <DD><UL>
767 | +html+ <LI><A HREF="http://www.tcx.se/Manual/manual.html#mysql_close">mysql_close()</A>
768 | +html+ </UL></DL>
769 |
770 | ++++++++++++++++++++++++++++++++++++++*/
771 | void SQ_close_connection(SQ_connection_t *sql_connection) {
772 |
773 | mysql_close(sql_connection);
774 |
775 | }
776 |
777 | /* SQ_num_rows() */
778 | /*++++++++++++++++++++++++++++++++++++++
779 | Call this function to find out how many rows are in a query result
780 |
781 | SQ_result_set_t *result The results.
782 |
783 | More:
784 | +html+ <PRE>
785 | Authors:
786 | ottrey
787 | +html+ </PRE><DL COMPACT>
788 | +html+ <DT>Online References:
789 | +html+ <DD><UL>
790 | +html+ <LI><A HREF="http://www.tcx.se/Manual/manual.html#mysql_num_rows">mysql_num_rows()</A>
791 | +html+ </UL></DL>
792 |
793 | ++++++++++++++++++++++++++++++++++++++*/
794 | int SQ_num_rows(SQ_result_set_t *result) {
795 | int rows=-1;
796 |
797 | if (result != NULL) {
798 | rows = mysql_num_rows(result);
799 | }
800 |
801 | return rows;
802 | }
803 |
804 | /* SQ_info_to_string() */
805 | /*++++++++++++++++++++++++++++++++++++++
806 | Convert all available information about the sql server into a string.
807 |
808 | SQ_connection_t *sql_connection The connection to the database.
809 |
810 | More:
811 | +html+ <PRE>
812 | Authors:
813 | ottrey
814 | +html+ </PRE><DL COMPACT>
815 | +html+ <DT>Online References:
816 | +html+ <DD><UL>
817 | +html+ </UL></DL>
818 |
819 | ++++++++++++++++++++++++++++++++++++++*/
820 | char *SQ_info_to_string(SQ_connection_t *sql_connection) {
821 | GString *buf;
822 | char *str_tmp;
823 | char *result;
824 |
825 | buf = g_string_sized_new(STR_XXL);
826 |
827 | /* Makes the server dump debug information to the log. */
828 | g_string_sprintfa(buf, "mysql_dump_debug_info()=%d\n",
829 | mysql_dump_debug_info(sql_connection));
830 |
831 | /* Returns the error number from the last MySQL function. */
832 | g_string_sprintfa(buf, "mysql_errno()=%d\n", mysql_errno(sql_connection));
833 |
834 | /* Returns the error message from the last MySQL function. */
835 | g_string_sprintfa(buf, "mysql_error()=%s\n", mysql_error(sql_connection));
836 |
837 | /* Returns client version information. */
838 | g_string_sprintfa(buf, "mysql_get_client_info()=%s\n",
839 | mysql_get_client_info() );
840 |
841 | /* Returns a string describing the connection. */
842 | g_string_sprintfa(buf, "mysql_get_host_info()=%s\n",
843 | mysql_get_host_info(sql_connection));
844 |
845 | /* Returns the protocol version used by the connection. */
846 | g_string_sprintfa(buf, "mysql_get_proto_info()=%d\n",
847 | mysql_get_proto_info(sql_connection));
848 |
849 | /* Returns the server version number. */
850 | g_string_sprintfa(buf, "mysql_get_server_info()=%s\n",
851 | mysql_get_server_info(sql_connection));
852 |
853 | /* Information about the most recently executed query. */
854 | str_tmp = mysql_info(sql_connection);
855 | if (str_tmp != NULL) {
856 | g_string_sprintfa(buf, "mysql_info()=\"%s\"\n", str_tmp);
857 | } else {
858 | g_string_append(buf, "mysql_info()=NULL\n");
859 | }
860 |
861 |
862 | /* Returns a list of the current server threads.
863 |
864 | NOT Used here, because it returns a RESULT struct that must be
865 | iterated through.
866 |
867 | sprintf(str_buffer_tmp, "mysql_list_processes()=%x\n", mysql_list_processes(sql_connection));
868 | strcat(str_buffer, str_buffer_tmp);
869 |
870 | */
871 |
872 | /* Checks if the connection to the server is working. */
873 | g_string_sprintfa(buf, "mysql_ping()=%d\n", mysql_ping(sql_connection));
874 |
875 | /* Returns the server status as a string. */
876 | g_string_sprintfa(buf, "mysql_stat()=%s\n", mysql_stat(sql_connection));
877 |
878 | /* Returns the current thread id. */
879 | g_string_sprintfa(buf, "mysql_thread_id()=%ld\n",
880 | mysql_thread_id(sql_connection));
881 |
882 |
883 | /* copy our string and return the copy */
884 | result = UT_strdup(buf->str);
885 | g_string_free(buf, TRUE);
886 | return result;
887 |
888 | } /* SQ_info_to_string() */
889 |
890 | /* SQ_error() */
891 | /*++++++++++++++++++++++++++++++++++++++
892 | Get the error string for the last error.
893 |
894 | SQ_connection_t *sql_connection The connection to the database.
895 |
896 | More:
897 | +html+ <PRE>
898 | Authors:
899 | ottrey
900 | +html+ </PRE><DL COMPACT>
901 | +html+ <DT>Online References:
902 | +html+ <DD><UL>
903 | +html+ <LI><A HREF="http://www.tcx.se/Manual/manual.html#mysql_error">mysql_error()</A>
904 | +html+ </UL></DL>
905 |
906 | ++++++++++++++++++++++++++++++++++++++*/
907 | char *SQ_error(SQ_connection_t *sql_connection) {
908 |
909 | return mysql_error(sql_connection);
910 |
911 | } /* SQ_error() */
912 |
913 | /* SQ_errno() */
914 | /*++++++++++++++++++++++++++++++++++++++
915 | Get the error number for the last error.
916 |
917 | SQ_connection_t *sql_connection The connection to the database.
918 |
919 | More:
920 | +html+ <PRE>
921 | Authors:
922 | ottrey
923 | +html+ </PRE><DL COMPACT>
924 | +html+ <DT>Online References:
925 | +html+ <DD><UL>
926 | +html+ <LI><A HREF="http://www.tcx.se/Manual/manual.html#mysql_free_result">mysql_free_result()</A>
927 | +html+ </UL></DL>
928 |
929 | ++++++++++++++++++++++++++++++++++++++*/
930 | int SQ_errno(SQ_connection_t *sql_connection) {
931 |
932 | return mysql_errno(sql_connection);
933 |
934 | } /* SQ_errno() */
935 |
936 | /* SQ_get_info() */
937 | /*++++++++++++++++++++++++++++++++++++++
938 | Get additional information about the most
939 | recently executed query.
940 |
941 | SQ_connection_t *sql_connection The connection to the database.
942 | int info[3] array of integers where information is stored
943 |
944 | The meaning of the numbers returned depends on the query type:
945 |
946 | info[SQL_RECORDS] - # of Records for INSERT
947 | info[SQL_MATCHES] - # of Matches for UPDATE
948 | info[SQL_DUPLICATES] - # of Duplicates
949 | info[SQL_WARNINGS] - # of Warnings
950 |
951 | More:
952 | +html+ <PRE>
953 | Authors:
954 | andrei
955 | +html+ </PRE><DL COMPACT>
956 | +html+ <DT>Online References:
957 | +html+ <DD><UL>
958 | +html+ <LI><A HREF="http://www.tcx.se/Manual/manual.html#mysql_info">mysql_info()</A>
959 | +html+ </UL></DL>
960 |
961 | ++++++++++++++++++++++++++++++++++++++*/
962 |
963 | int SQ_get_info(SQ_connection_t *sql_connection, int info[3])
964 | {
965 | int ii;
966 | char *colon, *buf_ptr, buf[20];
967 | char *infoline;
968 |
969 | infoline=mysql_info(sql_connection);
970 | ii=0;
971 | colon = infoline;
972 | while (*colon != '\0') {
973 | colon++;
974 | buf_ptr=buf;
975 | if(isdigit((int)*colon)){
976 | while(isdigit((int)*colon)){
977 | *buf_ptr=*colon; buf_ptr++; colon++;
978 | }
979 | *buf_ptr='\0';
980 | info[ii]=atoi(buf); ii++;
981 | }
982 | }
983 | return(0);
984 | }
985 |
986 |
987 | /*
988 | open a connection with the same parameters
989 |
990 | by marek
991 | */
992 | SQ_connection_t *
993 | SQ_duplicate_connection(SQ_connection_t *orig)
994 | {
995 | return SQ_get_connection(orig->host, orig->port, orig->db,
996 | orig->user, orig->passwd);
997 | }
998 |
999 | /*
1000 | abort the current query on the given connection
1001 |
1002 | by marek
1003 | */
1004 | int
1005 | SQ_abort_query(SQ_connection_t *sql_connection)
1006 | {
1007 | SQ_connection_t *contemp = SQ_duplicate_connection(sql_connection);
1008 | int res = mysql_kill(contemp, sql_connection->thread_id);
1009 |
1010 | ER_dbg_va(FAC_SQ, ASP_SQ_ABORT,
1011 | "connection %d aborted by tmp thread %d",
1012 | sql_connection->thread_id,
1013 | contemp->thread_id);
1014 |
1015 | SQ_close_connection(contemp);
1016 |
1017 | return res;
1018 | }
1019 |
1020 | /* SQ_ping() */
1021 | /*++++++++++++++++++++++++++++++++++++++
1022 | Checks whether or not the connection to the server is working.
1023 | If it has gone down, an automatic reconnection is attempted.
1024 |
1025 | Return values
1026 |
1027 | Zero if the server is alive. Non-zero if an error occurred.
1028 |
1029 | More:
1030 | +html+ <PRE>
1031 | Authors:
1032 | andrei
1033 | +html+ </PRE><DL COMPACT>
1034 | +html+ <DT>Online References:
1035 | +html+ <DD><UL>
1036 | +html+ </UL></DL>
1037 |
1038 | ++++++++++++++++++++++++++++++++++++++*/
1039 | int SQ_ping(SQ_connection_t *sql_connection)
1040 | {
1041 | return(mysql_ping(sql_connection));
1042 | }
1043 |
1044 | /************************************************************
1045 | * get_minmax_id() *
1046 | * *
1047 | * Returns the min or max ID of the table *
1048 | * *
1049 | * Returns: *
1050 | * min (max=0) or max (max=1) ID *
1051 | * -1 in case of an error *
1052 | * *
1053 | * *
1054 | *************************************************************/
1055 |
1056 | long sq_get_minmax_id(SQ_connection_t *sql_connection, char *id_name, char *table, int max)
1057 | {
1058 | GString *query;
1059 | SQ_result_set_t *sql_result;
1060 | SQ_row_t *sql_row;
1061 | char *sql_str;
1062 | long id;
1063 | char *minmax;
1064 | int sql_err;
1065 |
1066 | query = g_string_sized_new(STR_M);
1067 |
1068 | if(max==1)minmax="max"; else minmax="min";
1069 |
1070 | g_string_sprintf(query, "SELECT %s(%s) FROM %s ", minmax, id_name, table);
1071 |
1072 | sql_err = SQ_execute_query(sql_connection, query->str, &sql_result);
1073 |
1074 | if(sql_err) {
1075 | ER_perror(FAC_SQ, SQ_CNCT, "%s[%s]\n", SQ_error(sql_connection),
1076 | query->str);
1077 | die;
1078 | }
1079 |
1080 |
1081 | if ((sql_row = SQ_row_next(sql_result)) != NULL) {
1082 | sql_str = SQ_get_column_string(sql_result, sql_row, 0);
1083 |
1084 | /* We must process all the rows of the result,*/
1085 | /* otherwise we'll have them as part of the next qry */
1086 | while ( (sql_row = SQ_row_next(sql_result)) != NULL) {
1087 | ER_perror(FAC_SQ, SQ_CNCT, "duplicate max [%s]\n", query->str);
1088 | die;
1089 | }
1090 | }
1091 | else sql_str=NULL;
1092 |
1093 | if(sql_result){ SQ_free_result(sql_result); sql_result=NULL; }
1094 |
1095 | if(sql_str) {
1096 | id = atol(sql_str);
1097 | UT_free(sql_str);
1098 | }
1099 | /* table is empty, max_id=min_id=0 */
1100 | else id=0;
1101 |
1102 | /* free temporary space used for query */
1103 | g_string_free(query, TRUE);
1104 |
1105 | return(id);
1106 |
1107 | }
1108 |
1109 | /* SQ_escape_string() */
1110 | /*++++++++++++++++++++++++++++++++++++++
1111 | Returns a copy of the string passed that has been escaped so it
1112 | may be safely used in SQL strings.
1113 |
1114 | Return values
1115 |
1116 | Escaped string (allocated memory which must be freed)
1117 |
1118 | More:
1119 | +html+ <PRE>
1120 | Authors:
1121 | shane
1122 | +html+ </PRE><DL COMPACT>
1123 | +html+ <DT>Online References:
1124 | +html+ <DD><UL>
1125 | +html+ </UL></DL>
1126 |
1127 | ++++++++++++++++++++++++++++++++++++++*/
1128 |
1129 | char *SQ_escape_string(SQ_connection_t *sql_connection, char *str)
1130 | {
1131 | char *new_str;
1132 | int length;
1133 |
1134 | length = strlen(str);
1135 | new_str = (char *)UT_malloc((length * 2) + 1);
1136 | mysql_real_escape_string(sql_connection, new_str, str, length);
1137 | return new_str;
1138 | }
1139 |