/* 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 . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include static SCM s_mysql_mark(struct sql_connect *conn) { return SCM_BOOL_F; } static scm_sizet s_mysql_free(struct sql_connect *conn) { MYSQL *mysql = (MYSQL*) conn->data; if (!mysql) return 0; mysql_close(mysql); return sizeof(MYSQL); } 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", s_mysql_mark, s_mysql_free, s_mysql_connect, s_mysql_close, s_mysql_query, };