## modules/sq/mysql_driver.c

/* [<][>][^][v][top][bottom][index][help] */

## DEFINITIONS

This source file includes following functions.

1. SQ_try_connection
2. SQ_get_connection
3. SQ_execute_query
4. SQ_execute_query_nostore
5. SQ_get_column_count
6. SQ_get_table_size
7. SQ_get_affected_rows
8. SQ_get_insert_id
9. SQ_get_column_label
10. SQ_get_column_max_length
11. SQ_row_next
12. SQ_get_column_string
13. SQ_get_column_string_nocopy
14. SQ_get_column_strings
15. SQ_get_column_int
16. SQ_result_to_string
17. SQ_free_result
18. SQ_close_connection
19. SQ_num_rows
20. SQ_info_to_string
21. SQ_error
22. SQ_errno
23. SQ_get_info
24. SQ_duplicate_connection
25. SQ_abort_query
26. SQ_ping
27. sq_get_minmax_id
28. SQ_escape_string

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

/* [<][>][^][v][top][bottom][index][help] */