diff options
Diffstat (limited to 'src/gsql_conn.c')
-rw-r--r-- | src/gsql_conn.c | 205 |
1 files changed, 205 insertions, 0 deletions
diff --git a/src/gsql_conn.c b/src/gsql_conn.c new file mode 100644 index 0000000..a61f8f6 --- /dev/null +++ b/src/gsql_conn.c @@ -0,0 +1,205 @@ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include <string.h> +#include <guile-sql.h> +#include <app.h> + +int num_iface; +struct sql_iface sql_iftab[MAX_IFACES]; + +long sql_connect_tag; + +/* 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); + free(conn); + 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("#<SQL connection (", port); + scm_puts(sql_iftab[conn->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; +} + +int +sql_find_iface(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_LIST1(scm_makfrom0str(name))); + + conn = scm_must_malloc (sizeof (*conn), "sql_connect"); + memset(conn, 0, sizeof *conn); + conn->iface = iface; + SCM_RETURN_NEWSMOB (sql_connect_tag, conn); +} + +int +scm_is_sql_connect (SCM scm) +{ + return SCM_NIMP (scm) && SCM_CAR (scm) == sql_connect_tag; +} + +/* Interface */ + +SCM_DEFINE (sql_connect_internal, "sql-connect-internal", 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_internal +{ + SCM smob; + char *hostname; + int port; + char *dbname; + char *user; + char *pass; + int iface; + + if (SCM_IMP(IFACE) && SCM_INUMP(IFACE)) + iface = SCM_INUM(IFACE); + else if (SCM_STRINGP(IFACE)) + iface = sql_find_iface(SCM_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_LIST2(SCM_MAKINUM(1), + IFACE)); + + SCM_ASSERT(SCM_STRINGP(HOST), HOST, SCM_ARG1, FUNC_NAME); + hostname = SCM_ROCHARS(HOST); + + SCM_ASSERT(SCM_IMP(PORT) && SCM_INUMP(PORT), + PORT, SCM_ARG2, FUNC_NAME); + port = SCM_INUM(PORT); + + SCM_ASSERT(SCM_STRINGP(DB), DB, SCM_ARG3, FUNC_NAME); + dbname = SCM_ROCHARS(DB); + + SCM_ASSERT(SCM_STRINGP(USER), USER, SCM_ARG4, FUNC_NAME); + user = SCM_ROCHARS(USER); + + if (SCM_UNBNDP(PASS)) + pass = NULL; + else if (SCM_STRINGP(USER)) + pass = SCM_ROCHARS(PASS); + + smob = sql_iftab[iface].connect(hostname, port, + dbname, user, pass, + FUNC_NAME); + if (smob != SCM_BOOL_F) { + struct sql_connect *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_internal, "sql-query-internal", 2, 0, 0, + (SCM CONN, SCM QUERY), + "Run an SQL query") +#define FUNC_NAME s_sql_query_internal +{ + struct sql_connect *conn; + void *ptr; + char *query; + + SCM_ASSERT(scm_is_sql_connect(CONN), CONN, SCM_ARG1, FUNC_NAME); + SCM_ASSERT(SCM_STRINGP(QUERY), QUERY, SCM_ARG2, FUNC_NAME); + conn = (struct sql_connect *)SCM_CDR(CONN); + query = SCM_ROCHARS(QUERY); + return sql_iftab[conn->iface].query(conn, query); +} +#undef FUNC_NAME + +int +sql_register_iface(struct sql_iface *ifp) +{ + 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() +{ + 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); +#include <gsql_conn.x> +} |