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 |