/* 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,
};