modules/sq/mysql_driver.c

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

FUNCTIONS

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] */