00001
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include "../config.h"
00030
00031 #ifdef USE_MYSQL
00032 #include <stdlib.h>
00033 #include <stdio.h>
00034 #include <string.h>
00035 #include <mysql.h>
00036
00037 #include "buf.h"
00038 #include "db_conn.h"
00039
00040
00041
00043 #define BASENAME "Database"
00044
00046 #define BASEHOST "Host"
00047 #define BASEPORT "Port"
00048 #define BASELOGIN "Username"
00049
00051 #define BASEPASS "Password"
00052
00054 typedef struct {
00055 MYSQL *conn;
00056 char *dbname;
00057 DBTableDef *table_def;
00058 int table_num;
00059 } DBConnection_MYSQL;
00060
00061
00066 MYSQL_RES dummyRes;
00067
00069 static char *sqlKeywords[] = {
00070 "ABS", "AND", "ALTER", "ASC", "ASCII",
00071 "BEGIN", "BETWEEN", "BIN", "BINARY", "BIT_LENGTH",
00072 "CASE", "CEILING", "CHAR", "CHAR_LENGTH", "CHARACTER_LENGTH",
00073 "COALESCE", "COMMIT", "CONCAT", "CONCAT_WS", "CONV", "COUNT",
00074 "CREATE",
00075 "DATABASE", "DELETE", "DESC", "DESCRIBE", "DISTINCT", "DISTINCTROW",
00076 "DROP",
00077 "ELT", "END", "EXP", "EXPLAIN", "EXPORT_SET",
00078 "FIELD", "FIND_IN_SET", "FLOOR", "FROM",
00079 "GRANT", "GROUP BY",
00080 "HAVING", "HEX",
00081 "IFNULL", "INDEX", "INNER", "INSERT", "INSTR", "INTERVAL", "INTO",
00082 "ISNULL",
00083 "JOIN",
00084 "LCASE", "LEFT", "LENGTH", "LIKE", "LOAD DATA", "LOAD_FILE", "LOCATE",
00085 "LOCK", "LOG", "LOG2", "LOG10", "LOWER", "LPAD", "LTRIM",
00086 "MAKE_SET", "MATCH", "MAX", "MID", "MIN", "MEAN", "MOD",
00087 "NATURAL", "NOT", "NULL", "NULLIF",
00088 "OCT", "OCTET_LENGTH", "OR", "ORD", "ORDER BY", "OUTER",
00089 "POSITION", "POW", "POWER",
00090 "QUOTE",
00091 "REGEXP", "REPEAT", "REPLACE", "RESET", "REVERSE", "REVOKE", "RIGHT",
00092 "RLIKE", "ROLLBACK", "ROUND", "RPAD", "RTRIM",
00093 "SELECT", "SET", "SHOW", "SIGN", "SOUNDEX", "SPACE", "SQRT", "STRCMP",
00094 "SUBSTRING", "SUBSTRING_INDEX", "SUM",
00095 "TABLE", "THEN", "TRANSACTION",
00096 "UCASE", "UNION", "UPDATE", "UPPER",
00097 "WHEN", "WHERE", "WORK",
00098 NULL
00099 };
00100
00103 void mysql_dbconnection_free(DBConnection * dbconn)
00104 {
00105 DBConnection_MYSQL *dbmysql = (DBConnection_MYSQL *) (dbconn->pvt);
00106 free(dbmysql->dbname);
00107
00108
00109 keywords_remove_all(dbconn);
00110
00111
00112 free(dbmysql);
00113 free(dbconn);
00114 }
00115
00119 static int my_DBdisconnect(DBConnection * dbconn)
00120 {
00121 DBConnection_MYSQL *dbmysql = (DBConnection_MYSQL *) (dbconn->pvt);
00122 MYSQL *co = dbmysql->conn;
00123
00124
00125 mysql_close(co);
00126 mysql_dbconnection_free(dbconn);
00127 return 0;
00128 }
00129
00133 static char *my_DBget_error_message(DBConnection * dbconn)
00134 {
00135 DBConnection_MYSQL *dbmysql = (DBConnection_MYSQL *) (dbconn->pvt);
00136 return mysql_error(dbmysql->conn);
00137 }
00138
00142 static char *my_DBget_db_name(DBConnection * dbconn)
00143 {
00144 DBConnection_MYSQL *dbmysql = (DBConnection_MYSQL *) (dbconn->pvt);
00145 return dbmysql->dbname;
00146 }
00147
00152 static void *my_DBexecute_query(DBConnection * dbconn, char *query)
00153 {
00154 int fields;
00155 DBConnection_MYSQL *dbmysql = (DBConnection_MYSQL *) (dbconn->pvt);
00156 MYSQL_RES *res;
00157
00158 if (mysql_query(dbmysql->conn, query))
00159 return NULL;
00160
00161 res = mysql_store_result(dbmysql->conn);
00162
00163 if (res == NULL) {
00164 #ifdef HAVE_MYSQL_FIELD_COUNT
00165
00166 fields = mysql_field_count(dbmysql->conn);
00167 #else
00168 fields = mysql_num_fields(dbmysql->conn);
00169 #endif
00170 if (fields == 0)
00171 res = &dummyRes;
00172 }
00173 return res;
00174 }
00175
00176 static ABuf *f2ubuf = NULL;
00177
00181 char *my_DBform_to_url(Form *frm) {
00182 char *s;
00183
00184 if (frm == NULL)
00185 return NULL;
00186
00187 f2ubuf = buf_check(f2ubuf, 100);
00188 f2ubuf = buf_strcpy(f2ubuf, frm_get_title(frm));
00189 f2ubuf = buf_strcat(f2ubuf, "://");
00190 s = frm_get_value_by_name(frm, BASELOGIN);
00191 if (s != NULL) {
00192 f2ubuf = buf_strcat(f2ubuf, s);
00193 s = frm_get_value_by_name(frm, BASEPASS);
00194 if (s != NULL) {
00195 f2ubuf = buf_strcat(f2ubuf, ":");
00196 f2ubuf = buf_strcat(f2ubuf, s);
00197 }
00198 f2ubuf = buf_strcat(f2ubuf, "@");
00199 }
00200 s = frm_get_value_by_name(frm, BASEHOST);
00201 if (s == NULL)
00202 s = "localhost";
00203
00204 f2ubuf = buf_strcat(f2ubuf, s);
00205 f2ubuf = buf_strcat(f2ubuf, "/");
00206 s = frm_get_value_by_name(frm, BASENAME);
00207 if (s != NULL)
00208 f2ubuf = buf_strcat(f2ubuf, s);
00209
00210 return f2ubuf->b_dat;
00211 }
00212
00218 static int my_DBget_query_status(DBConnection * dbconn, void *result)
00219 {
00220 DBConnection_MYSQL *dbmysql = (DBConnection_MYSQL *) (dbconn->pvt);
00221 MYSQL_RES *res = result;
00222 char *err;
00223
00224 err = mysql_error(dbmysql->conn);
00225 if (err[0]) {
00226 return DB_QUERY_ERROR;
00227 }
00228 else if (res == &dummyRes) {
00229 return DB_QUERY_COMMAND_OK;
00230 }
00231 else if (mysql_num_rows(res) == 0) {
00232 return DB_QUERY_EMPTY;
00233 }
00234 else {
00235 return DB_QUERY_RECORDS_OK;
00236 }
00237 }
00238
00243 static int my_DBget_record_number(DBConnection * dbconn, void *result)
00244 {
00245 MYSQL_RES *res = result;
00246
00247 return mysql_num_rows(res);
00248 }
00249
00254 static int my_DBget_field_number(DBConnection * dbconn, void *result)
00255 {
00256 MYSQL_RES *res = result;
00257
00258 return mysql_num_fields(res);
00259 }
00260
00265 static char *my_DBget_field_name(DBConnection * dbconn, void *result, int field)
00266 {
00267 MYSQL_RES *res = result;
00268 MYSQL_FIELD *f;
00269
00270 mysql_field_seek(res, field);
00271 if ((f = mysql_fetch_field(res)) == NULL)
00272 return NULL;
00273 return f->name;
00274 }
00275
00282 static char *my_DBget_field_value(DBConnection * dbconn, void *result,
00283 int record, int field)
00284 {
00285 MYSQL_RES *res = result;
00286 MYSQL_ROW row;
00287
00288 mysql_data_seek(res, record);
00289 if ((row = mysql_fetch_row(res)) == NULL) {
00290 return NULL;
00291 }
00292 return (char *) row[field];
00293 }
00294
00298 static void my_DBclear_result(DBConnection * dbconn, void *result)
00299 {
00300 MYSQL_RES *res = result;
00301 if ((res) && (res != &dummyRes))
00302 mysql_free_result(res);
00303 }
00304
00309 static int my_add_field_def(DBConnection * dbconn, DBTableDef * tbf)
00310 {
00312 #define DESCRIBE_S "describe %s"
00313
00314 DBConnection_MYSQL *dbmysql = (DBConnection_MYSQL *) (dbconn->pvt);
00315 MYSQL *co = dbmysql->conn;
00316 MYSQL_RES *table_info;
00317 ABuf *query = NULL;
00318 ABuf *type_str = NULL;
00319 int i;
00320 char *fname;
00321 char *rtype, *rnotnull, *rhasdef;
00322
00323 query = buf_check(query, strlen(DESCRIBE_S) + strlen(tbf->name) + 1);
00324 if (!query) {
00325 fprintf(stderr, "add_field_def() cannot allocate memory for query string\n");
00326 return -1;
00327 }
00328
00329 snprintf(query->b_dat, query->b_len, DESCRIBE_S, tbf->name);
00330
00331 if (mysql_query(co, query->b_dat))
00332 return -1;
00333
00334 if ((table_info = mysql_store_result(co)) == NULL)
00335 return -1;
00336
00337 tbf->field_num = mysql_num_rows(table_info);
00338 tbf->field_def =
00339 (DBFieldDef *) malloc(tbf->field_num * sizeof(DBFieldDef));
00340
00341 for (i = 0; i < tbf->field_num; i++) {
00342 MYSQL_ROW row;
00343
00344 mysql_data_seek(table_info, i);
00345 row = mysql_fetch_row(table_info);
00346
00347 fname = row[0];
00348 add_keyword(dbconn, fname, KEYWORD_FIELD);
00349
00350 rtype = row[1];
00351 rnotnull = row[2];
00352 rhasdef = row[4];
00353
00354
00355 type_str = buf_new(256);
00356
00357 if (rhasdef)
00358 type_str = buf_check(type_str, strlen(rhasdef));
00359
00360 type_str = buf_strcpy(type_str, rtype);
00361
00362 if (strncmp(rnotnull, "YES", 3) == 0)
00363 type_str = buf_strcat(type_str, " not null");
00364
00365 if (rhasdef) {
00366 type_str = buf_strcat(type_str, " default");
00367 }
00368
00369 tbf->field_def[i].name = strdup(fname);
00370 tbf->field_def[i].type = strdup(type_str->b_dat);
00371 tbf->field_def[i].length = strdup("??");
00372 }
00373
00374 buf_free(query);
00375 buf_free(type_str);
00376
00377 return 0;
00378 }
00379
00384 static int my_DBget_table_def(DBConnection * dbconn)
00385 {
00386 DBConnection_MYSQL *dbmysql;
00387 char query[] = "show tables";
00388 MYSQL_RES *res;
00389
00390 if (dbconn == NULL) {
00391 fprintf(stderr, "WARNING: Could not get table definitions.\n");
00392 return -1;
00393 }
00394
00395 dbmysql = (DBConnection_MYSQL *) (dbconn->pvt);
00396 if (dbmysql->table_def != NULL) {
00397 fprintf(stderr, "Internal error (memory leak in my_DBget_table_def)...\n");
00398 return -1;
00399 }
00400
00401 if (mysql_query(dbmysql->conn, query)) {
00402 return -1;
00403 }
00404 if ((res = mysql_store_result(dbmysql->conn)) == NULL) {
00405 return -1;
00406 }
00407 else {
00408 int i;
00409 int tables_in_list = mysql_num_rows(res);
00410
00411
00412 dbmysql->table_num = tables_in_list;
00413 dbmysql->table_def = (DBTableDef *)
00414 malloc(tables_in_list * sizeof(DBTableDef));
00415
00416
00417 for (i = 0; i < tables_in_list; i++) {
00418 char *table_name;
00419 MYSQL_ROW row;
00420
00421 mysql_data_seek(res, i);
00422 row = mysql_fetch_row(res);
00423 table_name = row[0];
00424
00425
00426 dbmysql->table_def[i].name = strdup(table_name);
00427
00428
00429 if (my_add_field_def(dbconn, dbmysql->table_def + i) < 0) {
00430 dbmysql->table_def = NULL;
00431 return -1;
00432 }
00433
00434
00435 add_keyword(dbconn, table_name, KEYWORD_TABLE);
00436 }
00437
00438 mysql_free_result(res);
00439 }
00440 return 0;
00441 }
00442
00445 static void my_DBfree_table_def(DBConnection * dbconn)
00446 {
00447 DBConnection_MYSQL *dbmysql = (DBConnection_MYSQL *) (dbconn->pvt);
00448
00449 if (dbmysql->table_def == NULL) {
00450
00451
00452 return;
00453 }
00454 else {
00455 DBFieldDef *dbf;
00456 int i, j;
00457
00458 for (j = 0; j < dbmysql->table_num; j++) {
00459 int fnum = (dbmysql->table_def)[j].field_num;
00460
00461 if (dbmysql->table_def[j].name)
00462 free(dbmysql->table_def[j].name);
00463
00464 dbf = (dbmysql->table_def)[j].field_def;
00465 for (i = 0; i < fnum; i++) {
00466 free(dbf[i].name);
00467 free(dbf[i].type);
00468 }
00469 free(dbf);
00470 }
00471 free(dbmysql->table_def);
00472 dbmysql->table_def = NULL;
00473
00474
00475 keywords_remove(dbconn, KEYWORD_TABLE);
00476 keywords_remove(dbconn, KEYWORD_FIELD);
00477 }
00478 }
00479
00483 static int my_DBget_table_num(DBConnection * dbconn)
00484 {
00485 DBConnection_MYSQL *conn = (DBConnection_MYSQL *) (dbconn->pvt);
00486
00487 return conn->table_num;
00488 }
00489
00494 void my_DBurl_to_form(Form *frm, char *url) {
00495 char *u;
00496 char *p;
00497 char *start;
00498 char *end;
00499 char *username = NULL;
00500 char *password = NULL;
00501 char *host = NULL;
00502 char *port = NULL;
00503 char *database = NULL;
00504
00505
00506 frm_clear_fields(frm);
00507
00508 if (url == NULL)
00509 return;
00510
00511 u = strdup(url);
00512 start = u;
00513
00514
00515 p = strstr(start, "://");
00516 if (p != NULL) {
00517 p += 3;
00518
00519
00520 start = p;
00521 p = strchr(start, '@');
00522 if (p != NULL) {
00523 *p = '\0';
00524 end = p;
00525 username = strdup(start);
00526 p++;
00527 start = p;
00528 }
00529
00530
00531 p = strchr(start, '/');
00532 if (p == NULL) {
00533 host = strdup(start);
00534 }
00535 else {
00536 *p = '\0';
00537 host = strdup(start);
00538 p++;
00539 if (strlen(p) > 0)
00540 database = strdup(p);
00541 }
00542
00543
00544 if (username != NULL) {
00545 p = strchr(username, ':');
00546 if (p != NULL) {
00547 *p = '\0';
00548 p++;
00549 password = strdup(p);
00550 }
00551 }
00552
00553
00554 if (host != NULL) {
00555 p = strchr(host, ':');
00556 if (p != NULL) {
00557 *p = '\0';
00558 p++;
00559 port = strdup(p);
00560 }
00561 }
00562 }
00563
00564
00565 if (username != NULL) {
00566 frm_set_value_by_name(frm, BASELOGIN, username);
00567 free(username);
00568 }
00569
00570 if (password != NULL) {
00571 frm_set_value_by_name(frm, BASEPASS, password);
00572 free(password);
00573 }
00574
00575 if (host != NULL) {
00576 frm_set_value_by_name(frm, BASEHOST, host);
00577 free(host);
00578 }
00579
00580 #ifdef HAVE_MYSQL_REAL_CONNECT
00581 if (port != NULL) {
00582 frm_set_value_by_name(frm, BASEPORT, port);
00583 free(port);
00584 }
00585 #endif
00586
00587 if (database != NULL) {
00588 frm_set_value_by_name(frm, BASENAME, database);
00589 free(database);
00590 }
00591 free(u);
00592 }
00593
00598 static DBTableDef *my_DBget_table(DBConnection * dbconn, int table)
00599 {
00600 DBConnection_MYSQL *conn = (DBConnection_MYSQL *) (dbconn->pvt);
00601
00602 if (table > conn->table_num) {
00603 fprintf(stderr, "Internal error (table number too big)...\n");
00604 return NULL;
00605 }
00606
00607 if (conn->table_def == NULL) {
00608 fprintf(stderr, "Internal error (searching a NULL table)...\n");
00609 return NULL;
00610 }
00611 else {
00612 return conn->table_def + table;
00613 }
00614 }
00615
00618 DBConnection *mysql_dbconnection_new()
00619 {
00620 DBConnection *dbc = calloc(1, sizeof(DBConnection));
00621 if (dbc) {
00622 dbc->pvt = calloc(1, sizeof(DBConnection_MYSQL));
00623 if (dbc->pvt)
00624 dbc->pvtlen = sizeof(DBConnection_MYSQL);
00625 }
00626 return dbc;
00627 }
00628
00635 static int my_connect_callback(DBConnector * dbc, DBConnection ** ret)
00636 {
00638 #define DB_CONNECT_ERROR_S "Database connection error : \n %s"
00639 char *bname, *bhost, *blogin, *bpass;
00640 #ifdef HAVE_MYSQL_REAL_CONNECT
00641 char *bport;
00642 unsigned int portNo = 0;
00643 #endif
00644 ABuf *buf = NULL;
00645 char *db_err = NULL;
00646 MYSQL *my_conn = NULL;
00647 DBConnection *ret_my = NULL;
00648 DBConnection_MYSQL *ret_my_mysql = NULL;
00649 int i;
00650
00651 *ret = NULL;
00652
00653
00654 bname = frm_get_value_by_name(dbc->db_frm, BASENAME);
00655 bhost = frm_get_value_by_name(dbc->db_frm, BASEHOST);
00656 if ((bhost != NULL) && (strlen(bhost) == 0))
00657 bhost = NULL;
00658
00659 #ifdef HAVE_MYSQL_REAL_CONNECT
00660 bport = frm_get_value_by_name(dbc->db_frm, BASEPORT);
00661 if ((bport != NULL) && (strlen(bport) == 0))
00662 bport = NULL;
00663 #endif
00664
00665 blogin = frm_get_value_by_name(dbc->db_frm, BASELOGIN);
00666
00667 if ((blogin != NULL) && (strlen(blogin) == 0))
00668 blogin = NULL;
00669
00670 bpass = frm_get_value_by_name(dbc->db_frm, BASEPASS);
00671 if ((bpass != NULL) && (strlen(bpass) == 0))
00672 bpass = NULL;
00673
00674 if ((my_conn = calloc(1, sizeof(MYSQL))) == NULL) {
00675 return CONNECT_ERROR;
00676 }
00677
00678
00679 #ifdef HAVE_MYSQL_REAL_CONNECT
00680
00681 my_conn = mysql_init (my_conn);
00682 if (bport != NULL)
00683 portNo = atoi(bport);
00684
00685 if (!mysql_real_connect(my_conn, bhost, blogin, bpass, NULL, portNo, NULL, 0)) {
00686 #else
00687 if (!mysql_connect(my_conn, bhost, blogin, bpass)) {
00688 #endif
00689 db_err = mysql_error(my_conn);
00690 buf = buf_new(strlen(DB_CONNECT_ERROR_S) + strlen(db_err) + 1);
00691 if (!buf) {
00692 fprintf(stderr, "connect_callback() couldnt allocate memory for buffer\n");
00693 return CONNECT_ERROR;
00694 }
00695
00696 snprintf(buf->b_dat, buf->b_len, DB_CONNECT_ERROR_S, db_err);
00697
00698 dbc->app_error_dialog("Connection Error", buf->b_dat);
00699 buf = buf_free(buf);
00700 return CONNECT_ERROR;
00701 }
00702
00703 if (mysql_select_db(my_conn, bname)) {
00704 db_err = mysql_error(my_conn);
00705 buf =
00706 buf_check(buf,
00707 strlen(DB_CONNECT_ERROR_S) + strlen(db_err) + 1);
00708 if (!buf) {
00709 fprintf(stderr, "connect_callback() couldnt allocate memory for buffer\n");
00710 return CONNECT_ERROR;
00711 }
00712
00713 snprintf(buf->b_dat, buf->b_len, DB_CONNECT_ERROR_S, db_err);
00714 dbc->app_error_dialog("Connection Error", buf->b_dat);
00715 buf = buf_free(buf);
00716 return CONNECT_ERROR;
00717 }
00718
00719 ret_my = mysql_dbconnection_new();
00720 if (!ret_my)
00721 return CONNECT_ERROR;
00722
00723 ret_my->connector = dbc;
00724
00725 ret_my_mysql = (DBConnection_MYSQL *) (ret_my->pvt);
00726
00727
00728 ret_my_mysql->conn = my_conn;
00729
00730
00731 ret_my_mysql->dbname = strdup(bname);
00732
00733
00734 ret_my->DBclear_result = my_DBclear_result;
00735 ret_my->DBdisconnect = my_DBdisconnect;
00736 ret_my->DBexecute_query = my_DBexecute_query;
00737 ret_my->DBfree_table_def = my_DBfree_table_def;
00738 ret_my->DBget_db_name = my_DBget_db_name;
00739 ret_my->DBget_error_message = my_DBget_error_message;
00740 ret_my->DBget_field_name = my_DBget_field_name;
00741 ret_my->DBget_field_number = my_DBget_field_number;
00742 ret_my->DBget_field_value = my_DBget_field_value;
00743 ret_my->DBget_query_status = my_DBget_query_status;
00744 ret_my->DBget_record_number = my_DBget_record_number;
00745 ret_my->DBget_table = my_DBget_table;
00746 ret_my->DBget_table_def = my_DBget_table_def;
00747 ret_my->DBget_table_num = my_DBget_table_num;
00748
00749
00750 ret_my->keylist = NULL;
00751 i = 0;
00752 while (sqlKeywords[i] != NULL)
00753 add_keyword((DBConnection *) ret_my, sqlKeywords[i++],
00754 KEYWORD_SQL);
00755
00756 *ret = ret_my;
00757 buf = buf_free(buf);
00758 return CONNECT_OK;
00759 }
00760
00762 #define MYSQL_TYPESTR "MySQL"
00763
00768 DBConnector *register_MySQL(void (*error_dialog) (char *, char *))
00769 {
00770 DBConnector *dbconn;
00771 FormField *fld;
00772
00773 dbconn = dbconnector_new();
00774 if (dbconn == NULL)
00775 return NULL;
00776
00777 dbconn->dbtype = MYSQL_TYPESTR;
00778
00779
00780 dbconn->app_error_dialog = error_dialog;
00781 dbconn->db_connect_callback = my_connect_callback;
00782 dbconn->url_to_form = my_DBurl_to_form;
00783 dbconn->form_to_url = my_DBform_to_url;
00784
00785
00786 dbconn->db_frm = frm_new(NULL);
00787 frm_set_title(dbconn->db_frm, "MySQL");
00788 fld = frm_add_field(dbconn->db_frm, BASENAME, NULL);
00789 fld_set_tip(fld, "Database name (required)");
00790 fld_set_relevance(fld, FR_REQUIRED);
00791
00792 fld = frm_add_field(dbconn->db_frm, BASEHOST, NULL);
00793 fld_set_tip(fld, "Host running database (optional)");
00794
00795 #ifdef HAVE_MYSQL_REAL_CONNECT
00796 fld = frm_add_field(dbconn->db_frm, BASEPORT, NULL);
00797 fld_set_tip(fld, "Port database listens on (optional)");
00798 #endif
00799
00800 fld = frm_add_field(dbconn->db_frm, BASELOGIN, NULL);
00801 fld_set_tip(fld, "Username for connection (optional)");
00802
00803 fld = frm_add_field(dbconn->db_frm, BASEPASS, NULL);
00804 fld_set_type(fld, FT_PWD);
00805 fld_set_tip(fld, "Password for connection (optional)");
00806
00807 return dbconn;
00808 }
00809
00810 #endif