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