aboutsummaryrefslogtreecommitdiff
path: root/src/vmod-sql.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/vmod-sql.c')
-rw-r--r--src/vmod-sql.c294
1 files changed, 294 insertions, 0 deletions
diff --git a/src/vmod-sql.c b/src/vmod-sql.c
new file mode 100644
index 0000000..119fa25
--- /dev/null
+++ b/src/vmod-sql.c
@@ -0,0 +1,294 @@
+/* This file is part of vmod-sql
+ Copyright (C) 2013 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 <http://www.gnu.org/licenses/>.
+*/
+#include "vmod-sql.h"
+#include <stdarg.h>
+#include "wordsplit.h"
+#include "vrt.h"
+#include "vcc_if.h"
+#include "bin/varnishd/cache.h"
+
+static pthread_once_t thread_once = PTHREAD_ONCE_INIT;
+static pthread_key_t thread_key;
+
+void
+i_modsql_debug(const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vsyslog(LOG_DAEMON|LOG_DEBUG, fmt, ap);
+ va_end(ap);
+}
+
+void
+i_modsql_error(const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vsyslog(LOG_DAEMON|LOG_ERR, fmt, ap);
+ va_end(ap);
+}
+
+struct vmod_sql_connection *
+i_modsql_conntab_get(int n)
+{
+ struct vmod_sql_connection *conntab = pthread_getspecific(thread_key);
+ if (n < 0 || n > MAXCONN || !conntab || !conntab[n].backend)
+ return NULL;
+ return conntab + n;
+}
+
+int
+i_modsql_conntab_alloc(struct vmod_sql_connection *cp)
+{
+ int i;
+ struct vmod_sql_connection *conntab = pthread_getspecific(thread_key);
+ if (!conntab) {
+ conntab = calloc(MAXCONN, sizeof(conntab[0]));
+ AN(conntab);
+ AZ(pthread_setspecific(thread_key, conntab));
+ }
+
+ for (i = 0; i < MAXCONN; i++) {
+ if (conntab[i].backend == NULL) {
+ conntab[i] = *cp;
+ return i;
+ }
+ }
+ return -1;
+}
+
+static int
+i_modsql_conntab_find(const char *bkname, const char *param_str)
+{
+ int i;
+ struct vmod_sql_connection *conntab = pthread_getspecific(thread_key);
+ if (!conntab)
+ return -1;
+ for (i = 0; i < MAXCONN; i++) {
+ if (conntab[i].backend &&
+ strcmp(conntab[i].backend->name, bkname) == 0 &&
+ strcmp(conntab[i].param_str, param_str) == 0) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+
+static void
+conn_free(void *f)
+{
+ struct vmod_sql_connection *conntab = pthread_getspecific(thread_key);
+ if (conntab) {
+ struct vmod_sql_connection *cp;
+ for (cp = conntab; cp < conntab + MAXCONN; cp++) {
+ if (cp->state != state_init) {
+ i_modsql_disconnect(cp);
+ i_modsql_destroy(cp);
+ }
+ }
+ }
+ free(conntab);
+}
+
+static void
+make_key()
+{
+ pthread_key_create(&thread_key, conn_free);
+}
+
+int
+module_init(struct vmod_priv *priv, const struct VCL_conf *vclconf)
+{
+ pthread_once(&thread_once, make_key);
+ return 0;
+}
+
+char *
+i_modsql_findparam(char **params, char *name)
+{
+ char *p, *q;
+
+ while (*params) {
+ p = *params++;
+ for (q = name; *p && *q && *p == *q; p++, q++);
+ if (*q == 0 && *p == '=')
+ return p+1;
+ }
+ return NULL;
+}
+
+
+static struct vmod_sql_backend *bcktab[] = {
+#ifdef USE_SQL_MYSQL
+ &i_modsql_mysql_backend,
+#endif
+#ifdef USE_SQL_PGSQL
+ &i_modsql_pgsql_backend,
+#endif
+ NULL
+};
+
+static struct vmod_sql_backend *
+find_backend(const char *name)
+{
+ int i;
+
+ for (i = 0; bcktab[i]; i++) {
+ if (strcmp(bcktab[i]->name, name) == 0)
+ return bcktab[i];
+ }
+ return NULL;
+}
+
+int
+vmod_connect(struct sess *sp, struct vmod_priv *priv, const char *bkname,
+ const char *param)
+{
+ struct wordsplit ws;
+ struct vmod_sql_backend *be;
+ int n;
+
+ n = i_modsql_conntab_find(bkname, param);
+ if (n != -1)
+ return n;
+ ws.ws_delim = ";";
+ if (wordsplit(param, &ws,
+ WRDSF_NOVAR | WRDSF_NOCMD | WRDSF_QUOTE |
+ WRDSF_CESCAPES |
+ WRDSF_DELIM)) {
+ i_modsql_error("cannot split string `%s': %s",
+ param, wordsplit_strerror(&ws));
+ return -1;
+ }
+
+ /* Select backend */
+ be = find_backend(bkname);
+ if (!be) {
+ i_modsql_error("unsupported backend: %s", bkname);
+ wordsplit_free(&ws);
+ return -1;
+ }
+
+ n = i_modsql_create_connection(be, param, ws.ws_wordv);
+ ws.ws_wordc = 0;
+ ws.ws_wordv = NULL;
+ wordsplit_free(&ws);
+ return n;
+}
+
+void
+vmod_connect_init(struct sess *sp, struct vmod_priv *priv, const char *bkname,
+ const char *param)
+{
+ AZ(vmod_connect(sp, priv, bkname, param));
+}
+
+static struct vmod_sql_connection *
+runquery(struct sess *sp, int n, const char *query, const char *arg)
+{
+ struct vmod_sql_connection *cp;
+ struct wordsplit ws, wsenv;
+ int i, rc;
+
+ cp = i_modsql_conntab_get(n);
+ if (!cp)
+ return NULL;
+ debug(cp, 2, ("runquery(%s) begin", arg));
+
+ if (cp->state != state_connected)
+ return NULL;
+
+ debug(cp, 2, ("runquery: splitting arg"));
+ wsenv.ws_delim = ";";
+ if (wordsplit(arg, &wsenv, WRDSF_NOVAR|WRDSF_NOCMD|WRDSF_DELIM)) {
+ i_modsql_error("cannot split string `%s': %s",
+ arg, wordsplit_strerror(&wsenv));
+ return NULL;
+ }
+
+ if (cp->backend->be_escape) {
+ debug(cp, 2, ("escaping variables"));
+ for (i = 0; i < wsenv.ws_wordc; i++) {
+ char *p = i_modsql_escape(cp, wsenv.ws_wordv[i]);
+ if (!p) {
+ i_modsql_error("cannot expand argument");
+ wordsplit_free(&wsenv);
+ return NULL;
+ }
+ free(wsenv.ws_wordv[i]);
+ wsenv.ws_wordv[i] = p;
+ debug(cp, 3, ("%d: %s",i,p));
+ }
+ }
+
+ debug(cp, 2, ("expanding query"));
+ ws.ws_env = (const char **)wsenv.ws_wordv;
+ rc = wordsplit(query, &ws,
+ WRDSF_NOCMD | WRDSF_QUOTE |
+ WRDSF_NOSPLIT |
+ WRDSF_ENV | WRDSF_UNDEF);
+ if (rc) {
+ i_modsql_error("cannot expand query `%s': %s",
+ query, wordsplit_strerror(&ws));
+ wordsplit_free(&wsenv);
+ return NULL;
+ }
+
+ rc = i_modsql_query(cp, ws.ws_wordv[0]);
+ wordsplit_free(&ws);
+ wordsplit_free(&wsenv);
+
+ return cp;
+}
+
+unsigned
+vmod_query(struct sess *sp, struct vmod_priv *priv, int cd, const char *query,
+ const char *arg)
+{
+ return !runquery(sp, cd, query, arg);
+}
+
+const char *
+vmod_result(struct sess *sp, struct vmod_priv *priv, int cd, int row, int col)
+{
+ struct vmod_sql_connection *cp;
+ const char *s;
+
+ cp = i_modsql_conntab_get(cd);
+ if (!cp)
+ return NULL;
+
+ s = i_modsql_get_column(cp, row, col);
+
+ if (!s)
+ return NULL;
+ return WS_Dup(sp->ws, s);
+}
+
+int
+vmod_affected(struct sess *sp, struct vmod_priv *priv, int cd)
+{
+ struct vmod_sql_connection *cp;
+
+ cp = i_modsql_conntab_get(cd);
+ if (!cp)
+ return 0;
+ return i_modsql_affected_rows(cp);
+}
+
+

Return to:

Send suggestions and report system problems to the System administrator.