Source File sq/mysql_driver.c

    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,
    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) {
    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,
    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,
    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) {
    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,
    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)
    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)
    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) {
    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) {
    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) {
    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) {
    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,
    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) {
    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) {
    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) {
    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) {
    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) {
    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) {
    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) {
    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) {
    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) {
    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])
    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)
    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)
    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)
    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)
    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)
    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 |