Source File modules/sq/mysql_driver.c

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