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