aboutsummaryrefslogtreecommitdiff
path: root/gamma/gsql_conn.c
diff options
context:
space:
mode:
Diffstat (limited to 'gamma/gsql_conn.c')
-rw-r--r--gamma/gsql_conn.c257
1 files changed, 257 insertions, 0 deletions
diff --git a/gamma/gsql_conn.c b/gamma/gsql_conn.c
new file mode 100644
index 0000000..64cec27
--- /dev/null
+++ b/gamma/gsql_conn.c
@@ -0,0 +1,257 @@
+/* This file is part of Gamma.
+ Copyright (C) 2002, 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 <app.h>
+#include <stdio.h>
+
+static int num_iface;
+static struct sql_iface sql_iftab[MAX_IFACES];
+
+SCM_GLOBAL_SYMBOL (gamma_sql_error, "sql-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);
+ if (sql_iftab[conn->iface].mark)
+ return sql_iftab[conn->iface].mark(conn);
+}
+
+static size_t
+sql_connect_free(SCM connect_smob)
+{
+ struct sql_connect *conn = (struct sql_connect *)SCM_CDR(connect_smob);
+ 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 0;
+}
+
+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("#<SQL connection (", port);
+ scm_puts(sql_iftab[conn->iface].name, port);
+ scm_puts(")", port);
+ if (!conn->data)
+ scm_puts("not connected", port);
+ else {
+ static const char *unspecified = "<unspecified>";
+ scm_puts(conn->username ? conn->username : unspecified, port);
+ scm_puts("@", port);
+ scm_puts(conn->hostname ? conn->hostname : unspecified, port);
+ scm_puts(":", port);
+ scm_intprint(conn->port, 10, port);
+ scm_puts(" ", port);
+ scm_puts(conn->database ? conn->database : unspecified, 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_from_locale_string(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 */
+
+static void
+gamma_cvt_iface(SCM inval, void *outval, const char *func_name)
+{
+ int iface;
+
+ if (scm_is_integer(inval))
+ iface = scm_to_int(inval);
+ else if (scm_is_string(inval)) {
+ char *s = scm_to_locale_string(inval);
+ iface = sql_find_iface(s);
+ free(s);
+ } else
+ SCM_ASSERT(0, inval, SCM_ARG1, func_name);
+
+ if (iface < 0 || iface >= num_iface)
+ scm_misc_error(func_name,
+ "Argument ~S (~S) out of range",
+ scm_list_2(scm_from_int(1),
+ inval));
+ *(int*)outval = iface;
+}
+
+
+SCM_DEFINE_PUBLIC(sql_open_connection, "sql-open-connection", 1, 0, 0,
+ (SCM param),
+"Connect to a database. Take connection parameters from @var{param}, "
+"which must be a list of conses. In each cons, the @samp{car} contains "
+"a @dfn{key} identifying the parameter, and the @samp{cdr} supplies the "
+"value for that parameter.\n"
+"\n"
+"Valid keys are:\n"
+"@table @asis\n"
+"@item #:iface\n"
+"Defines the type of the @acronym{SQL} interface (either @samp{mysql} or "
+"@samp{postgres}.\n"
+"@item #:host\n"
+"Server host name.\n"
+"@item #:port\n"
+"Port number on @samp{#:host}.\n"
+"@item #:socket\n"
+"Socket path, if the server is listening on a UNIX socket. Either\n"
+"@samp{#:port} or @samp{#:socket} may be given, but not both.\n"
+"@item #:user\n"
+"Sets the @acronym{SQL} user name.\n"
+"@item #:pass\n"
+"Sets the password for @samp{#:user}\n"
+"@item #:ssl-cert\n"
+"Full pathname of the @acronym{SSL} certificate to use (MySQL only).\n"
+"@item #:config-file\n"
+"Read missing parameters from the specified file (MySQL only).\n"
+"@item #:config-group\n"
+"Read the specified group in the config file (MySQL only).\n"
+"@end table\n")
+#define FUNC_NAME s_sql_open_connection
+{
+ int iface;
+
+ struct gamma_parmdcl dcltab[] = {
+ { "iface", &iface, gamma_cvt_iface },
+ { NULL }
+ };
+
+ SCM smob;
+
+ SCM_ASSERT(scm_is_pair(param), param, SCM_ARG1, FUNC_NAME);
+ gamma_parmlist_parse (param, dcltab,
+ GAMMA_PARMLIST_IGNORE_UNKNOWN, FUNC_NAME);
+
+ smob = sql_iftab[iface].connect(param, FUNC_NAME);
+
+ return smob;
+}
+#undef FUNC_NAME
+
+SCM_DEFINE_PUBLIC(sql_close_connection, "sql-close-connection", 1, 0, 0,
+ (SCM conn),
+ "Close connection to a database.")
+#define FUNC_NAME s_sql_close_connection
+{
+ struct sql_connect *cp;
+ SCM_ASSERT(scm_is_sql_connect(conn), conn, SCM_ARG1, FUNC_NAME);
+ cp = (struct sql_connect *)SCM_CDR(conn);
+ sql_iftab[cp->iface].close(cp);
+ return SCM_UNSPECIFIED;
+}
+#undef FUNC_NAME
+
+SCM_DEFINE_PUBLIC(sql_query, "sql-query", 2, 0, 0,
+ (SCM conn, SCM query),
+"Send the SQL query @var{query} to the server using connection @var{conn} \
+and return the result.\n\
+If @var{query} is a @samp{SELECT}, or similar query, returning tuples, the \
+return value is a list of rows. Each row is a list of values, one for each \
+column. All values are returned as strings. NULL values are returned as \
+@samp{#f}.\n\n\
+If @var{query} is an @samp{UPDATE} (or a similar query), @code{sql-query} \
+returns number of rows affected by the query.\n")
+#define FUNC_NAME s_sql_query
+{
+ struct sql_connect *conn_ptr;
+ char *query_ptr;
+ SCM ret;
+
+ SCM_ASSERT(scm_is_sql_connect(conn), conn, SCM_ARG1, FUNC_NAME);
+ SCM_ASSERT(scm_is_string(query), query, SCM_ARG2, FUNC_NAME);
+ conn_ptr = (struct sql_connect *)SCM_CDR(conn);
+ query_ptr = scm_to_locale_string(query);
+ ret = sql_iftab[conn_ptr->iface].query(conn_ptr, query_ptr);
+ free(query_ptr);
+ return ret;
+}
+#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 <gsql_conn.x>
+#endif
+}
+
+

Return to:

Send suggestions and report system problems to the System administrator.