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

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

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