diff options
Diffstat (limited to 'contrib/pginterface/pginterface.c')
-rw-r--r-- | contrib/pginterface/pginterface.c | 212 |
1 files changed, 212 insertions, 0 deletions
diff --git a/contrib/pginterface/pginterface.c b/contrib/pginterface/pginterface.c new file mode 100644 index 00000000000..58f7cfa7eb6 --- /dev/null +++ b/contrib/pginterface/pginterface.c @@ -0,0 +1,212 @@ +/* + * pginterface.c + * +*/ + +#include <stdio.h> +#include <signal.h> +#include <string.h> +#include <stdarg.h> + +#include <libpq-fe.h> +#include "halt.h" +#include "pginterface.h" + +static void sig_disconnect(); +static void set_signals(); + +#define NUL '\0' + +/* GLOBAL VARIABLES */ +static PGconn* conn; +static PGresult* res = NULL; + +#define ON_ERROR_STOP 0 +#define ON_ERROR_CONTINUE 1 + +static int on_error_state = ON_ERROR_STOP; + +/* LOCAL VARIABLES */ +static sigset_t block_sigs, unblock_sigs; +static int tuple; + +/* +** +** connectdb - returns PGconn structure +** +*/ +PGconn *connectdb( char *dbName, + char *pghost, + char *pgport, + char *pgoptions, + char *pgtty) +{ + /* make a connection to the database */ + conn = PQsetdb(pghost, pgport, pgoptions, pgtty, dbName); + if (PQstatus(conn) == CONNECTION_BAD) + halt("Connection to database '%s' failed.\n%s\n", dbName, + PQerrorMessage(conn)); + set_signals(); + return conn; +} + +/* +** +** disconnectdb +** +*/ +void disconnectdb() +{ + PQfinish(conn); +} + +/* +** +** doquery - returns PGresult structure +** +*/ +PGresult *doquery(char *query) +{ + if (res != NULL) + PQclear(res); + + sigprocmask(SIG_SETMASK,&block_sigs,NULL); + res = PQexec(conn, query); + sigprocmask(SIG_SETMASK,&unblock_sigs,NULL); + + if (on_error_state == ON_ERROR_STOP && + (res == NULL || + PQresultStatus(res) == PGRES_BAD_RESPONSE || + PQresultStatus(res) == PGRES_NONFATAL_ERROR || + PQresultStatus(res) == PGRES_FATAL_ERROR)) + { + if (res != NULL) + fprintf(stderr,"query error: %s\n",PQcmdStatus(res)); + else fprintf(stderr,"connection error: %s\n",PQerrorMessage(conn)); + PQfinish(conn); + halt("failed request: %s\n", query); + } + tuple = 0; + return res; +} + +/* +** +** fetch - returns tuple number (starts at 0), or the value END_OF_TUPLES +** NULL pointers are skipped +** +*/ +int fetch(void *param, ...) +{ + va_list ap; + int arg, num_args; + + num_args = PQnfields(res); + + if (tuple >= PQntuples(res)) + return END_OF_TUPLES; + + va_start(ap, param); + for (arg = 0; arg < num_args; arg++) + { + if (param != NULL) + { + if (PQfsize(res, arg) == -1) + { + memcpy(param,PQgetvalue(res,tuple,arg),PQgetlength(res,tuple,arg)); + ((char *)param)[PQgetlength(res,tuple,arg)] = NUL; + } + else + memcpy(param,PQgetvalue(res,tuple,arg),PQfsize(res,arg)); + } + param = va_arg(ap, char *); + } + va_end(ap); + return tuple++; +} + +/* +** +** fetchisnull - returns tuple number (starts at 0), or the value END_OF_TUPLES +** NULL pointers are skipped +** Returns true or false into null indicator variables +*/ +int fetchisnull(void *param, ...) +{ + va_list ap; + int arg, num_args; + + if (tuple == 0) + halt("pginterface:fetchisnull(): You must call fetch() first.\n"); + + num_args = PQnfields(res); + + if (tuple-1 >= PQntuples(res)) + return END_OF_TUPLES; + va_start(ap, param); + for (arg = 0; arg < num_args; arg++) + { + if (param != NULL) + { + if (PQgetisnull(res,tuple-1,arg) != 0) + *(int *)param = 1; + else + *(int *)param = 0; + } + param = va_arg(ap, char *); + } + va_end(ap); + return tuple-1; +} + +/* +** +** on_error_stop +** +*/ +void on_error_stop() +{ + on_error_state = ON_ERROR_STOP; +} + +/* +** +** on_error_continue +** +*/ +void on_error_continue() +{ + on_error_state = ON_ERROR_CONTINUE; +} + +/* +** +** sig_disconnect +** +*/ +static void sig_disconnect() +{ + fprintf(stderr,"exiting...\n"); + PQfinish(conn); + exit(1); +} + +/* +** +** set_signals +** +*/ +static void set_signals() +{ + sigemptyset(&block_sigs); + sigemptyset(&unblock_sigs); + sigaddset(&block_sigs,SIGTERM); + sigaddset(&block_sigs,SIGHUP); + sigaddset(&block_sigs,SIGINT); +/* sigaddset(&block_sigs,SIGQUIT); no block */ + sigprocmask(SIG_SETMASK,&unblock_sigs,NULL); + signal(SIGTERM,sig_disconnect); + signal(SIGHUP,sig_disconnect); + signal(SIGINT,sig_disconnect); + signal(SIGQUIT,sig_disconnect); +} |