/* This file is part of vmod-sql
Copyright (C) 2013-2014 Sergey Poznyakoff
Vmod-sql 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.
Vmod-sql 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 vmod-sql. If not, see .
*/
#include "vmod-sql.h"
#include
#include
#define CONN_ASSERT(conn) do { \
if (!(conn)->backend) \
return; \
if ((conn)->state == state_disabled) \
return; \
} while(0)
#define CONN_ASSERT_VAL(conn,v) do { \
if (!(conn)->backend) \
return v; \
if ((conn)->state == state_disabled) \
return v; \
} while(0)
int
i_modsql_init(struct vmod_sql_connection *conn)
{
CONN_ASSERT_VAL(conn, 1);
debug(conn, 3, ("i_modsql_init called"));
if (conn->backend->be_init)
return conn->backend->be_init(conn);
return 0;
}
static void
argv_free(char **argv)
{
if (!argv)
return;
while (*argv) {
free(*argv);
++*argv;
}
}
void
i_modsql_destroy(struct vmod_sql_connection *conn)
{
CONN_ASSERT(conn);
debug(conn, 5, ("i_modsql_destroy: state=%d", conn->state));
do {
switch (conn->state) {
case state_init:
break;
case state_result:
i_modsql_free_result(conn);
break;
case state_connected:
i_modsql_disconnect(conn);
break;
default:
/* Force destroy */
conn->state = state_init;
}
} while (conn->state != state_init);
if (conn->backend->be_destroy)
return conn->backend->be_destroy(conn);
argv_free(conn->param);
conn->backend = NULL;
}
int
i_modsql_connect(struct vmod_sql_connection *conn)
{
CONN_ASSERT_VAL(conn, 1);
debug(conn, 5, ("sql_connect: state=%d", conn->state));
switch (conn->state) {
case state_init:
break;
case state_connected:
case state_result:
return 0;
case state_error:
i_modsql_disconnect(conn);
if (conn->state != state_init)
return 1;
break;
case state_disabled:
return 1;
}
assert(conn->backend->be_connect);
if (conn->backend->be_connect(conn))
return 1;
debug(conn, 5, ("sql_connect: success"));
conn->state = state_connected;
return 0;
}
int
i_modsql_create_connection(struct vmod_sql_backend *be, const char *ps,
char **param)
{
struct vmod_sql_connection conn;
int i;
const char *s;
conn.state = state_init;
conn.data = NULL;
conn.param = param;
conn.backend = be;
conn.param_str = strdup(ps);
s = i_modsql_findparam(param, "debug");
conn.debug_level = s ? atoi(s) : 0;
if (i_modsql_init(&conn))
return -1;
if (i_modsql_connect(&conn))
return -1;
i = i_modsql_conntab_alloc(&conn);
if (i == -1) {
i_modsql_disconnect(&conn);
i_modsql_destroy(&conn);
}
return i;
}
void
i_modsql_disconnect(struct vmod_sql_connection *conn)
{
CONN_ASSERT(conn);
debug(conn, 5, ("i_modsql_disconnect: state=%d", conn->state));
assert(conn->backend->be_disconnect);
if (conn->backend->be_disconnect(conn) == 0)
conn->state = state_init;
}
char *
i_modsql_escape(struct vmod_sql_connection *conn, const char *input)
{
CONN_ASSERT_VAL(conn, NULL);
debug(conn, 5, ("i_modsql_escape: state=%d; input=%s",
conn->state, input));
if (conn->backend->be_escape)
return conn->backend->be_escape(conn, input);
return strdup(input);
}
int
i_modsql_query(struct vmod_sql_connection *conn, const char *input)
{
CONN_ASSERT_VAL(conn, 1);
debug(conn, 1, ("state=%d, query=%s", conn->state, input));
do {
switch (conn->state) {
case state_init:
if (i_modsql_connect(conn) ||
conn->state != state_connected)
return 1;
break;
case state_connected:
break;
case state_result:
i_modsql_free_result(conn);
break;
case state_error:
i_modsql_disconnect(conn);
if (conn->state != state_init)
return 1;
break;
default:
return 1;
}
} while (conn->state != state_connected);
if (conn->backend->be_query(conn, input) == 0)
return 0;
return 1;
}
unsigned
i_modsql_num_tuples(struct vmod_sql_connection *conn)
{
CONN_ASSERT_VAL(conn, 0);
assert(conn->backend->be_num_tuples);
return conn->backend->be_num_tuples(conn);
}
unsigned
i_modsql_num_fields(struct vmod_sql_connection *conn)
{
CONN_ASSERT_VAL(conn, 0);
assert(conn->backend->be_num_fields);
return conn->backend->be_num_fields(conn);
}
void
i_modsql_free_result(struct vmod_sql_connection *conn)
{
CONN_ASSERT(conn);
if (conn->backend->be_free_result) {
if (conn->backend->be_free_result(conn))
return;
}
conn->state = state_connected;
}
const char *
i_modsql_get_column(struct vmod_sql_connection *conn, unsigned row,
unsigned col)
{
CONN_ASSERT_VAL(conn, NULL);
assert(conn->backend->sql_get_column);
if (conn->state != state_result)
return NULL;
return conn->backend->sql_get_column(conn, row, col);
}
long
i_modsql_affected_rows(struct vmod_sql_connection *conn)
{
CONN_ASSERT_VAL(conn, 0);
assert(conn->backend->be_affected_rows);
if (conn->state != state_connected)
return 0;
return conn->backend->be_affected_rows(conn);
}