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