/* This file is part of vmod-dbrw
Copyright (C) 2013-2014 Sergey Poznyakoff
Vmod-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.
Vmod-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 vmod-dbrw. If not, see .
*/
#include "dbrw.h"
#include "wordsplit.h"
#include
#include
#include
#include
const char *progname;
void
dbrw_debug(const char *fmt, ...)
{
va_list ap;
fprintf(stderr, "%s: DEBUG: ", progname);
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
fputc('\n', stderr);
}
void
dbrw_error(const char *fmt, ...)
{
va_list ap;
fprintf(stderr, "%s: ", progname);
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
fputc('\n', stderr);
}
void
usage(int c)
{
FILE *fp = c ? stderr : stdout;
fprintf(fp, "usage: %s [-ch] BACKEND CONN\n", progname);
fprintf(fp, "Initializes the test database\n\n");
fprintf(fp, "BACKEND is mysql or pgsql\n");
fprintf(fp, "CONN is the vmod-dbrw connection parameter string\n");
fprintf(fp, "(see second argument to dbrw.config in vmod-dbrw(1))\n");
fprintf(fp, "\nOPTIONS:\n\n");
fprintf(fp, " -c create the database if it does not exist\n");
fprintf(fp, " -h print this help summary\n");
exit(c);
}
int line;
char *qbuf;
size_t qsize;
size_t qlen;
int
iscomm(const char *p)
{
for (; *p; p++) {
if (*p == '-' && p[1] == '-')
return 1;
if (!isspace(*p))
return 0;
}
return 1;
}
char *
getquery(FILE *fp)
{
size_t len;
size_t off;
qlen = off = 0;
while (1) {
if (qlen + 1 >= qsize) {
if (qsize == 0)
qsize = 80;
else
qsize *= 2;
qbuf = realloc(qbuf, qsize);
if (!qbuf) {
dbrw_error("out of memory");
abort();
}
}
++line;
if (!fgets(qbuf + qlen, qsize - qlen, fp))
break;
len = strlen(qbuf + qlen);
qlen += len;
len = qlen;
if (qbuf[len - 1] != '\n')
continue;
while (len > 0 && isspace(qbuf[len - 1]))
--len;
if (iscomm(qbuf + off)) {
qlen = off;
continue;
} else
off = qlen;
if (qbuf[len - 1] == ';') {
qlen = len - 1;
break;
}
}
if (qlen == 0)
return NULL;
qbuf[qlen] = 0;
return qbuf;
}
void
trycreate(struct dbrw_connection *conn, const char *dbname)
{
char q[1024];
if (strcmp(conn->conf->backend->name, "mysql") == 0) {
snprintf(q, sizeof q, "CREATE DATABASE IF NOT EXISTS %s",
dbname);
if (sql_query(conn, q)) {
dbrw_error("query failed: %s", q);
exit(4);
}
} else {
snprintf(q, sizeof q,
"SELECT datname FROM pg_database WHERE datname='%s'",
dbname);
if (sql_query(conn, q)) {
dbrw_error("query failed: %s", q);
exit(4);
}
if (sql_num_tuples(conn) == 0) {
snprintf(q, sizeof q, "CREATE DATABASE %s",
dbname);
if (sql_query(conn, q)) {
dbrw_error("query failed: %s", q);
exit(4);
}
}
}
}
int
main(int argc, char **argv)
{
char *s;
struct wordsplit ws;
struct dbrw_config cfg;
struct dbrw_connection conn;
char buf[1024];
char *p;
char *dbname = NULL;
int create = 0;
int c;
int i;
progname = argv[0];
while ((c = getopt(argc, argv, "ch")) != EOF) {
switch (c) {
case 'c':
create = 1;
break;
case 'h':
usage(0);
break;
default:
return 1;
}
}
argc -= optind;
argv += optind;
if (argc != 2)
usage(1);
memset(&cfg, 0, sizeof(cfg));
cfg.backend = dbrw_backend_select(argv[0]);
if (!cfg.backend) {
dbrw_error("unsupported backend: %s", argv[0]);
return 1;
}
ws.ws_delim = ";";
wordsplit(argv[1], &ws,
WRDSF_NOVAR | WRDSF_NOCMD | WRDSF_QUOTE |
WRDSF_CESCAPES |
WRDSF_DELIM |
WRDSF_SHOWERR|WRDSF_ENOMEMABRT);
cfg.param = ws.ws_wordv;
ws.ws_wordv = NULL;
ws.ws_wordc = 0;
wordsplit_free(&ws);
if (create) {
for (i = 0; cfg.param[i]; i++)
if (strncmp(cfg.param[i], "database=", 9) == 0)
break;
if (!cfg.param[i]) {
dbrw_error("no database specified");
return 1;
}
dbname = cfg.param[i];
for (; cfg.param[i+1]; i++)
cfg.param[i] = cfg.param[i + 1];
if (strcmp(cfg.backend->name, "pgsql") == 0) {
cfg.param[i] = "database=postgres";
cfg.param[i + 1] = NULL;
} else
cfg.param[i] = NULL;
}
s = findparam(cfg.param, "debug");
cfg.debug_level = s ? atoi(s) : 0;
/* Initialize the connection */
memset(&conn, 0, sizeof(conn));
conn.state = state_init;
conn.conf = &cfg;
if (sql_init(&conn))
return 2;
if (sql_connect(&conn) || conn.state != state_connected)
return 2;
if (dbname) {
trycreate(&conn, dbname + 9);
cfg.param[i] = dbname;
cfg.param[i+1] = NULL;
sql_disconnect(&conn);
if (sql_connect(&conn) || conn.state != state_connected)
return 2;
}
line = 0;
while ((p = getquery(stdin))) {
if (sql_query(&conn, p)) {
dbrw_error("input line %d: query failed: %s",
line, p);
return 4;
}
}
sql_disconnect(&conn);
sql_destroy(&conn);
return 0;
}