/* This file is part of guile-sql.
Copyright (C) 2002, 2005 Sergey Poznyakoff
This program 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 of the License, or (at your
option) any later version.
This program 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 this program. If not, see . */
#ifdef HAVE_CONFIG_H
# include
#endif
#include
#include
#include
#include
static int num_iface;
static struct sql_iface sql_iftab[MAX_IFACES];
SCM_GLOBAL_SYMBOL (gsql_error, "gsql-error");
static long sql_connect_tag = -1;
/* SMOB functions: */
static SCM
sql_connect_mark (SCM connect_smob)
{
struct sql_connect *conn = (struct sql_connect *)SCM_CDR(connect_smob);
return sql_iftab[conn->iface].mark(conn);
}
static scm_sizet
sql_connect_free (SCM connect_smob)
{
scm_sizet size = sizeof(struct sql_connect);
struct sql_connect *conn = (struct sql_connect *)SCM_CDR(connect_smob);
size += sql_iftab[conn->iface].free(conn);
if (conn->hostname)
free(conn->hostname);
if (conn->username)
free(conn->username);
if (conn->database)
free(conn->database);
scm_gc_free(conn, sizeof *conn, "SQL connection");
return size;
}
static int
sql_connect_print (SCM connect_smob, SCM port, scm_print_state * pstate)
{
struct sql_connect *conn = (struct sql_connect *)SCM_CDR(connect_smob);
scm_puts("#iface].name, port);
scm_puts(")", port);
if (!conn->data)
scm_puts("not connected", port);
else {
scm_puts(conn->username, port);
scm_puts("@", port);
scm_puts(conn->hostname, port);
scm_puts(":", port);
scm_intprint(conn->port, 10, port);
scm_puts(" ", port);
scm_puts(conn->database, port);
};
scm_puts (">", port);
return 1;
}
static int
sql_find_iface(const char *name)
{
int iface;
for (iface = 0; iface < num_iface; iface++)
if (strcmp(sql_iftab[iface].name, name) == 0)
return iface;
return -1;
}
SCM
sql_connect_create (char *name)
{
struct sql_connect *conn;
int iface = sql_find_iface(name);
if (iface < 0)
scm_misc_error("sql_connect_create",
"Unknown SQL interface ~S",
scm_list_1(scm_makfrom0str(name)));
conn = scm_gc_malloc (sizeof (*conn), "sql_connect");
memset(conn, 0, sizeof *conn);
conn->iface = iface;
SCM_RETURN_NEWSMOB (sql_connect_tag, conn);
}
static int
scm_is_sql_connect (SCM scm)
{
return SCM_NIMP (scm) && SCM_CAR (scm) == (SCM) sql_connect_tag;
}
/* Interface */
SCM_DEFINE (sql_connect, "sql-connect", 5, 1, 0,
(SCM IFACE, SCM HOST, SCM PORT, SCM DB, SCM USER, SCM PASS),
"Connect to a database.")
#define FUNC_NAME s_sql_connect
{
SCM smob;
const char *hostname;
int port;
const char *dbname;
const char *user;
const char *pass;
int iface;
struct sql_connect *conn;
if (scm_is_integer(IFACE))
iface = scm_to_int(IFACE);
else if (scm_is_string(IFACE))
iface = sql_find_iface(scm_i_string_chars(IFACE));
else {
SCM_ASSERT(IFACE == SCM_BOOL_T || IFACE == SCM_BOOL_F,
IFACE, SCM_ARG1, FUNC_NAME);
iface = 0;
}
if (iface < 0 || iface >= num_iface)
scm_misc_error(FUNC_NAME,
"Argument ~S (~S) out of range",
scm_list_2(scm_from_int(1),
IFACE));
SCM_ASSERT(scm_is_string(HOST), HOST, SCM_ARG1, FUNC_NAME);
hostname = scm_i_string_chars(HOST);
SCM_ASSERT(scm_is_number(PORT), PORT, SCM_ARG2, FUNC_NAME);
port = scm_to_int(PORT);
SCM_ASSERT(scm_is_string(DB), DB, SCM_ARG3, FUNC_NAME);
dbname = scm_i_string_chars(DB);
SCM_ASSERT(scm_is_string(USER), USER, SCM_ARG4, FUNC_NAME);
user = scm_i_string_chars(USER);
if (SCM_UNBNDP(PASS))
pass = NULL;
else if (scm_is_string(USER))
pass = scm_i_string_chars(PASS);
smob = sql_iftab[iface].connect(hostname, port,
dbname, user, pass,
FUNC_NAME);
conn = (struct sql_connect *)SCM_CDR(smob);
conn->hostname = strdup(hostname);
conn->port = port;
conn->username = strdup(user);
conn->database = strdup(dbname);
return smob;
}
#undef FUNC_NAME
SCM_DEFINE (sql_connect_close, "sql-connect-close", 1, 0, 0,
(SCM CONN),
"Close connection to a database.")
#define FUNC_NAME s_sql_connect_close
{
struct sql_connect *conn;
SCM_ASSERT(scm_is_sql_connect(CONN), CONN, SCM_ARG1, FUNC_NAME);
conn = (struct sql_connect *)SCM_CDR(CONN);
sql_iftab[conn->iface].close(conn);
return SCM_UNSPECIFIED;
}
#undef FUNC_NAME
SCM_DEFINE (sql_query, "sql-query", 2, 0, 0,
(SCM CONN, SCM QUERY),
"Run an SQL query")
#define FUNC_NAME s_sql_query
{
struct sql_connect *conn;
void *ptr;
const char *query;
SCM_ASSERT(scm_is_sql_connect(CONN), CONN, SCM_ARG1, FUNC_NAME);
SCM_ASSERT(scm_is_string(QUERY), QUERY, SCM_ARG2, FUNC_NAME);
conn = (struct sql_connect *)SCM_CDR(CONN);
query = scm_i_string_chars(QUERY);
return sql_iftab[conn->iface].query(conn, query);
}
#undef FUNC_NAME
int
sql_register_iface(struct sql_iface *ifp)
{
int n = sql_find_iface(ifp->name);
if (n != -1)
return n;
if (num_iface >= MAX_IFACES)
scm_misc_error("sql_register_iface",
"Too many ifaces registered",
SCM_EOL);
memcpy(&sql_iftab[num_iface], ifp, sizeof sql_iftab[0]);
sql_iftab[num_iface].name = strdup(ifp->name);
return num_iface++;
}
void
gsql_conn_init()
{
if (sql_connect_tag == -1) {
sql_connect_tag = scm_make_smob_type ("sql_connect",
sizeof (struct sql_connect));
scm_set_smob_mark (sql_connect_tag, sql_connect_mark);
scm_set_smob_free (sql_connect_tag, sql_connect_free);
scm_set_smob_print (sql_connect_tag, sql_connect_print);
}
#ifndef SCM_MAGIC_SNARFER
# include
#endif
}