diff options
Diffstat (limited to 'gamma/mysql.c')
-rw-r--r-- | gamma/mysql.c | 227 |
1 files changed, 227 insertions, 0 deletions
diff --git a/gamma/mysql.c b/gamma/mysql.c new file mode 100644 index 0000000..dcc1847 --- /dev/null +++ b/gamma/mysql.c @@ -0,0 +1,227 @@ +/* This file is part of Gamma. + Copyright (C) 2002, 2004, 2005, 2010 Sergey Poznyakoff + + Gamma is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + Gamma is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Gamma. If not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include <string.h> +#include <guile-sql.h> +#include <mysql/mysql.h> + +static size_t +s_mysql_free(struct sql_connect *conn) +{ + MYSQL *mysql = (MYSQL*) conn->data; + if (mysql) + mysql_close(mysql); + return 0; +} + +static SCM +s_mysql_connect(SCM parmlist, const char *func_name) +{ + char *hostname = NULL; + int port = 0; + char *dbname = NULL; + char *user = NULL; + char *pass = NULL; + char *socket_path = NULL; + char *ssl_cert = NULL; + char *config_file = NULL; + char *config_group = NULL; + struct gamma_parmdcl dcltab[] = { + { "iface", NULL, NULL }, + { "host", &hostname, gamma_cvt_string }, + { "socket", &socket_path, gamma_cvt_string }, + { "port", &port, gamma_cvt_int }, + { "db", &dbname, gamma_cvt_string }, + { "user", &user, gamma_cvt_string }, + { "pass", &pass, gamma_cvt_string }, + { "ssl-cert", &ssl_cert, gamma_cvt_string }, + { "config-file", &config_file, gamma_cvt_string }, + { "config-group", &config_group, gamma_cvt_string }, + { NULL } + }; + + MYSQL *mysql, *mp; + SCM smob; + struct sql_connect *conn; + + gamma_parmlist_parse (parmlist, dcltab, 0, func_name); + + mysql = mysql_init(NULL); + + if (!mysql) + scm_error(gamma_sql_error, + func_name, + "~A", + scm_list_1(scm_from_locale_string("mysql_init() failed")), + SCM_BOOL_F); + + if (hostname && hostname[0] == '/') { + socket_path = hostname; + hostname = strdup ("localhost"); + } + + if (config_file) { + mysql_options (mysql, MYSQL_READ_DEFAULT_FILE, config_file); + free(config_file); + } + if (config_group) { + mysql_options (mysql, MYSQL_READ_DEFAULT_GROUP, config_group); + free(config_group); + } + if (ssl_cert) { + mysql_ssl_set (mysql, NULL, NULL, ssl_cert, NULL, NULL); + free(ssl_cert); + } + + mp = mysql_real_connect(mysql, hostname, + user, pass, dbname, + port, socket_path, + CLIENT_MULTI_RESULTS); + free(socket_path); + + if (!mp) { + SCM args, mdiag; + + free(hostname); + free(user); + free(pass); + free(dbname); + + mdiag = scm_from_locale_string(mysql_error(mysql)); + args = scm_list_2(scm_from_uint(mysql_errno(mysql)), + mdiag); + mysql_close(mysql); + + scm_error(gamma_sql_error, func_name, + "~A: ~A", + scm_list_2(scm_from_locale_string("Cannot connect to the database"), mdiag), + args); + } + + smob = sql_connect_create("mysql"); + conn = (struct sql_connect *)SCM_CDR(smob); + conn->hostname = hostname; + conn->port = port; + conn->username = user; + conn->database = dbname; + conn->data = mysql; + return smob; +} + +static void +flush_result(MYSQL *mysql) +{ + while (mysql_next_result(mysql) == 0) { + MYSQL_RES *result = mysql_store_result(mysql); + if (!result) + break; + if (mysql_field_count(mysql)) + while (mysql_fetch_row(result)) + ; + mysql_free_result(result); + } +} + +static SCM +s_mysql_query(struct sql_connect *conn, const char *query) +{ + MYSQL *mysql = conn->data; + MYSQL_RES *result; + SCM cell = SCM_EOL; + + if (mysql_query(mysql, query)) { + SCM mdiag = scm_from_locale_string(mysql_error(mysql)); + + scm_error(gamma_sql_error, "sql-query", + "~A: ~A", + scm_list_2(scm_from_locale_string("Error executing MySQL query"), + mdiag), + scm_list_2(scm_from_uint(mysql_errno(mysql)), + mdiag)); + } + + result = mysql_store_result(mysql); + + if (result) { + int nfields = mysql_num_fields(result); + int nrows = mysql_num_rows(result); + int i, j; + SCM row_head = SCM_EOL, row_tail = SCM_EOL; + + for (i = 0; i < nrows; i++) { + SCM new_row; + SCM head = SCM_EOL, tail = SCM_EOL; + MYSQL_ROW row = mysql_fetch_row(result); + + if (!row) + break; + for (j = 0; j < nfields; j++) { + SCM new_elt = + scm_cons(row[j] ? + scm_from_locale_string(row[j]) : + SCM_BOOL_F, + SCM_EOL); + if (head == SCM_EOL) + head = new_elt; + else + SCM_SETCDR(tail, new_elt); + tail = new_elt; + } + + new_row = scm_cons(head, SCM_EOL); + if (row_head == SCM_EOL) + row_head = new_row; + else + SCM_SETCDR(row_tail, new_row); + row_tail = new_row; + } + cell = row_head; + mysql_free_result(result); + flush_result(mysql); + } else { /* should it have returned something? */ + if (mysql_field_count(mysql) == 0) { + cell = scm_from_ulong(mysql_affected_rows(mysql)); + } else { /* mysql_store_result() should have returned data */ + scm_error(gamma_sql_error, "sql-query", + "~A", + scm_list_1(scm_from_locale_string("Query should have returned data")), + scm_list_2(scm_from_uint(mysql_errno(mysql)), + scm_from_locale_string(mysql_error(mysql)))); + } + } + return cell; +} + +static void +s_mysql_close(struct sql_connect *conn) +{ + if (conn->data) + mysql_close(conn->data); + conn->data = NULL; +} + +struct sql_iface mysql_iface = { + "mysql", + NULL, /* mark */ + s_mysql_free, + s_mysql_connect, + s_mysql_close, + s_mysql_query, +}; + |