diff options
Diffstat (limited to 'src/pgsql.c')
-rw-r--r-- | src/pgsql.c | 191 |
1 files changed, 188 insertions, 3 deletions
diff --git a/src/pgsql.c b/src/pgsql.c index e67e26c..3599b5f 100644 --- a/src/pgsql.c +++ b/src/pgsql.c @@ -1,7 +1,192 @@ -/* This file is a placeholder */ +/* This file is part of libvmod_dbrw + Copyright (C) 2013 Sergey Poznyakoff + + Libvmod_dbrw 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. + + Libvmod_dbrw 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 libvmod_dbrw. If not, see <http://www.gnu.org/licenses/>. +*/ #include "dbrw.h" +#include <string.h> +#include <libpq-fe.h> + +#define ISSPACE(c) ((c) == ' ' || (c) == '\t') + +static char * +chop(char *str) +{ + int len; + + if (!str) + return NULL; + for (len = strlen(str); len > 0 && ISSPACE(str[len-1]); len--) + ; + str[len] = 0; + return str; +} + +struct vmod_pgsql_data +{ + PGconn *pgconn; + PGresult *res; +}; + +static int +s_pgsql_init(struct dbrw_connection *conn) +{ + struct vmod_pgsql_data *dp = calloc (1, sizeof (*dp)); + if (!dp) + return ENOMEM; + conn->data = dp; + return 0; +} + +static void +s_pgsql_destroy(struct dbrw_connection *conn) +{ + struct vmod_pgsql_data *dp = conn->data; + free(dp); + conn->data = NULL; +} + +static int +s_pgsql_connect(struct dbrw_connection *conn) +{ + struct vmod_pgsql_data *dp = conn->data; + + dp->pgconn = PQsetdbLogin(findparam(conn->conf->param, "server"), + findparam(conn->conf->param, "port"), + findparam(conn->conf->param, "options"), + NULL, + findparam(conn->conf->param, "database"), + findparam(conn->conf->param, "user"), + findparam(conn->conf->param, "password")); + + if (PQstatus(dp->pgconn) == CONNECTION_BAD) { + dbrw_error("connection to the database failed: %s", + PQerrorMessage(dp->pgconn)); + PQfinish(dp->pgconn); + dp->pgconn = NULL; + return 1; + } + + return 0; +} + +static int +s_pgsql_disconnect(struct dbrw_connection *conn) +{ + struct vmod_pgsql_data *dp = conn->data; + PQfinish(dp->pgconn); + return 0; +} + +static int +s_pgsql_query(struct dbrw_connection *conn, const char *query) +{ + struct vmod_pgsql_data *dp = conn->data; + ExecStatusType stat; + + dp->res = PQexec(dp->pgconn, query); + stat = PQresultStatus(dp->res); + + if (stat != PGRES_COMMAND_OK && stat != PGRES_TUPLES_OK) { + dbrw_error("query failed: %s", PQerrorMessage(dp->pgconn)); + dbrw_error("the failed query was: %s", query); + if (dp->res) { + PQclear(dp->res); + dp->res = NULL; + } + return 1; + } + + return 0; +} + +static int +s_pgsql_free_result(struct dbrw_connection *conn) +{ + struct vmod_pgsql_data *dp = conn->data; + + PQclear(dp->res); + dp->res = NULL; + + return 0; +} + +static unsigned +s_pgsql_num_fields(struct dbrw_connection *conn) +{ + struct vmod_pgsql_data *dp = conn->data; + if (!dp->res) + return 0; + return PQnfields(dp->res); +} + +static unsigned +s_pgsql_num_tuples(struct dbrw_connection *conn) +{ + struct vmod_pgsql_data *dp = conn->data; + if (!dp->res) + return 0; + return PQntuples(dp->res); +} + +static const char * +s_pgsql_get_column(struct dbrw_connection *conn, size_t nrow, size_t ncol) +{ + struct vmod_pgsql_data *dp = conn->data; + + if (!dp->res) + return NULL; + return chop(PQgetvalue(dp->res, nrow, ncol)); +} + +static char * +s_pgsql_escape(struct dbrw_connection *conn, const char *ustr) +{ + char *str, *q; + const unsigned char *p; + size_t len = strlen(ustr); +#define ESCAPABLE_CHAR "\\'\"" + + for (p = (const unsigned char *) ustr; *p; p++) { + if (strchr(ESCAPABLE_CHAR, *p)) + len++; + } + + str = malloc(len + 1); + if (!str) + return NULL; + + for (p = (const unsigned char *) ustr, q = str; *p; p++) { + if (strchr(ESCAPABLE_CHAR, *p)) + *q++ = '\\'; + *q++ = *p; + } + *q = 0; + return str; +} + -static struct dbrw_backend pgsql_backend = { +struct dbrw_backend pgsql_backend = { "pgsql", - /* FIXME */ + s_pgsql_init, + s_pgsql_destroy, + s_pgsql_connect, + s_pgsql_disconnect, + s_pgsql_escape, + s_pgsql_query, + s_pgsql_num_tuples, + s_pgsql_num_fields, + s_pgsql_free_result, + s_pgsql_get_column }; |