summaryrefslogtreecommitdiffabout
authorSergey Poznyakoff <gray@gnu.org.ua>2013-07-14 12:49:09 (GMT)
committer Sergey Poznyakoff <gray@gnu.org.ua>2013-07-14 12:49:09 (GMT)
commit7111da4edcbff6f8a27af53bb340e31ea3c25867 (patch) (side-by-side diff)
tree94034d41cb9fc26c3382408f3d2ef83c9cbfd385
parent72ccd492bcf4979e6de11569a46ea47040897865 (diff)
downloadvmod-dbrw-7111da4edcbff6f8a27af53bb340e31ea3c25867.tar.gz
vmod-dbrw-7111da4edcbff6f8a27af53bb340e31ea3c25867.tar.bz2
Add PostgreSQL support.
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--README5
-rw-r--r--configure.ac71
-rw-r--r--src/pgsql.c191
3 files changed, 224 insertions, 43 deletions
diff --git a/README b/README
index b177149..a7f7636 100644
--- a/README
+++ b/README
@@ -8,8 +8,7 @@ structure, considerably speeding up their handling. Another advantage
of this approach is that rewrite rules stored in a database are easier
to maintain.
-This version supports MySQL databases. Support for PostgreSQL will be
-added soon.
+This version supports MySQL and PostgreSQL databases.
* Example
@@ -37,7 +36,7 @@ sub vcl_recv {
set req.http.X-Redirect-To =
dbrw.rewrite("host=" + req.http.Host + ";" +
"url=" + req.url);
- if (req.http.X-Redirect-To) {
+ if (req.http.X-Redirect-To != "") {
error(750, "Redirect");
}
}
diff --git a/configure.ac b/configure.ac
index 1ace670..09d56fa 100644
--- a/configure.ac
+++ b/configure.ac
@@ -96,61 +96,58 @@ fi
###########
# Check for SQL support
-build_mysqlmap=probe
-build_pgsqlmap=no #FIXME
+build_mysql=probe
+build_pgsql=probe
AC_ARG_WITH(mysql,
AC_HELP_STRING([--without-mysql],
[Configure to work without MySQL]),
- [build_mysqlmap=$withval])
+ [build_mysql=$withval])
AC_ARG_WITH(pgsql,
AC_HELP_STRING([--without-pgsql],
[Configure to work without Postgres]),
- [build_pgsqlmap=$withval])
+ [build_pgsql=$withval])
AC_ARG_WITH(postgres,
AC_HELP_STRING([--without-postgres],
[Same as --without-pgsql]),
- [build_pgsqlmap=$withval])
+ [build_pgsql=$withval])
-GR_ENABLE(mysqlmap, [
+GR_ENABLE(mysql, [
GR_CHECK_LIB(mysqlclient, mysql_real_connect, "-lm",
[ AC_DEFINE(USE_SQL_MYSQL,1,
[Define this if you are going to use MySQL])
AC_DEFINE(HAVE_LIBMYSQL,1,
[Define this if you have mysqlclient library])
MYSQLLIBS="$pm_cv_lib_mysqlclient"
- SQL_MODULES="$SQL_MODULES mysqlmap.la"
- build_mysqlmap=yes ],
- [ test "$build_mysqlmap" = yes && AC_MSG_ERROR([cannot build the requested module mysqlmap, because MySQL libraries are not present])
- build_mysqlmap=no ],
- [/usr/lib/mysql /usr/local/lib/mysql])], $build_mysqlmap)
-
-dnl FIXME
-dnl GR_ENABLE(pgsqlmap, [
-dnl GR_CHECK_LIB(pq, PQconnectStart, [],
-dnl [ save_CPPFLAGS=$CPPFLAGS
-dnl for dir in /usr/local/pgsql/include /usr/pgsql/include
-dnl do
-dnl CPPFLAGS="$save_CPPFLAGS -I$dir"
-dnl AC_CHECK_HEADER([libpq-fe.h], [break])
-dnl CPPFLAGS="$save_CPPFLAGS"
-dnl done
-dnl AC_DEFINE(USE_SQL_PGSQL,1,
-dnl [Define this if you are going to use PostgreSQL])
-dnl AC_DEFINE(HAVE_LIBPQ,1,
-dnl [Define this if you have libpq])
-dnl PGSQLLIBS="$pm_cv_lib_pq"
-dnl SQL_MODULES="$SQL_MODULES pgsqlmap.la"
-dnl build_pgsqlmap=yes ],
-dnl [ test "$build_pgsqlmap" = yes && AC_MSG_ERROR([cannot build the requested module pgsqlmap, because PostgreSQL libraries are not present])
-dnl build_pgsqlmap=no ],
-dnl [/usr/pgsql/lib /usr/local/pgsql/lib])], $build_pgsqlmap)
+ build_mysql=yes ],
+ [ test "$build_mysql" = yes && AC_MSG_ERROR([MySQL support cannot be built because MySQL libraries are not present])
+ build_mysql=no ],
+ [/usr/lib/mysql /usr/local/lib/mysql])], $build_mysql)
+
+GR_ENABLE(pgsql, [
+ GR_CHECK_LIB(pq, PQconnectStart, [],
+ [ save_CPPFLAGS=$CPPFLAGS
+ for dir in /usr/local/pgsql/include /usr/pgsql/include
+ do
+ CPPFLAGS="$save_CPPFLAGS -I$dir"
+ AC_CHECK_HEADER([libpq-fe.h], [break])
+ CPPFLAGS="$save_CPPFLAGS"
+ done
+ AC_DEFINE(USE_SQL_PGSQL,1,
+ [Define this if you are going to use PostgreSQL])
+ AC_DEFINE(HAVE_LIBPQ,1,
+ [Define this if you have libpq])
+ PGSQLLIBS="$pm_cv_lib_pq"
+ build_pgsql=yes ],
+ [ test "$build_pgsql" = yes && AC_MSG_ERROR([PostgreSQL support cannot be built because PostgreSQL libraries are not present])
+ build_pgsql=no ],
+ [/usr/pgsql/lib /usr/local/pgsql/lib])], $build_pgsql)
AC_SUBST(MYSQLLIBS)
AC_SUBST(PGSQLLIBS)
-AM_CONDITIONAL([USE_MYSQL],[test $build_mysqlmap = yes])
-AM_CONDITIONAL([USE_PGSQL],[test $build_pgsqlmap = yes])
+AM_CONDITIONAL([USE_MYSQL],[test $build_mysql = yes])
+AM_CONDITIONAL([USE_PGSQL],[test $build_pgsql = yes])
AC_CONFIG_COMMANDS([status],[
echo ""
@@ -158,7 +155,7 @@ delim="-------------------------------------------------------------------"
echo $delim | tr '-' '*'
echo "Backends to build:"
res=
-for module in mysqlmap pgsqlmap
+for module in mysql pgsql
do
eval enable=\${build_$module}
str=`echo ${module}" yes" | sed 's/./-/g'`
@@ -173,8 +170,8 @@ case "$res" in
AC_MSG_ERROR([Nothing to build?])
esac
],[
-build_pgsqlmap=$build_pgsqlmap
-build_mysqlmap=$build_mysqlmap])
+build_pgsql=$build_pgsql
+build_mysql=$build_mysql])
dnl FIXME: tests/Makefile
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
};

Return to:

Send suggestions and report system problems to the System administrator.