diff options
Diffstat (limited to 'contrib/pginterface')
| -rw-r--r-- | contrib/pginterface/Makefile | 19 | ||||
| -rw-r--r-- | contrib/pginterface/README | 42 | ||||
| -rw-r--r-- | contrib/pginterface/halt.c | 58 | ||||
| -rw-r--r-- | contrib/pginterface/halt.h | 7 | ||||
| -rw-r--r-- | contrib/pginterface/pginsert.c | 98 | ||||
| -rw-r--r-- | contrib/pginterface/pginterface.c | 177 | ||||
| -rw-r--r-- | contrib/pginterface/pginterface.h | 13 |
7 files changed, 414 insertions, 0 deletions
diff --git a/contrib/pginterface/Makefile b/contrib/pginterface/Makefile new file mode 100644 index 0000000000..7759ef8d28 --- /dev/null +++ b/contrib/pginterface/Makefile @@ -0,0 +1,19 @@ +# +# Makefile +# +# +TARGET = pginsert +CFLAGS = -g -Wall -I/u/postgres95/include +LIBS = -L/u/postgres95/lib -lpq + +$(TARGET) : pginsert.o pginterface.o halt.o + $(CC) -o $(TARGET) $(XFLAGS) $(CFLAGS) \ + pginsert.o pginterface.o halt.o $(LIBS) + +clean: + rm -f *.o $(TARGET) log core + +install: + make clean + make CFLAGS=-O + install -s -o bin -g bin $(TARGET) /usr/local/bin diff --git a/contrib/pginterface/README b/contrib/pginterface/README new file mode 100644 index 0000000000..5062431f09 --- /dev/null +++ b/contrib/pginterface/README @@ -0,0 +1,42 @@ + + + Pginterface 1.0 + +Attached is a copy of the Postgres support routines I wrote to allow me +to more cleanly interface to the libpg library, more like a 4gl SQL +interface. + +It has several features that may be useful for others: + +I have simplified the C code that calls libpq by wrapping all the +functionality of libpq in calls to connectdb(), doquery(), fetch(), and +disconnectdb(). Each call returns a structure or value, so if you need +to do more work with the result, you can. Also, I have a global +variable that allows you to disable the error checking I have added to +the doquery() routine. + +I have added a function called fetch(), which allows you to pass +pointers as parameters, and on return the variables are filled with the +data from the binary cursor you opened. These binary cursors are not +useful if you are running the query engine on a system with a different +architecture than the database server. If you pass a NULL pointer, the +column is skipped, and you can use libpq to handle it as you wish. + +I have used sigprocmask() to block the reception of certain signals +while the program is executing SQL queries. This prevents a user +pressing Control-C from stopping all the back ends. It blocks SIGHUP, +SIGINT, and SIGTERM, but does not block SIGQUIT or obviously kill -9. +If your platform does not support sigprocmask(), you can remove those +function calls. ( Am I correct that abnormal termination can cause +shared memory resynchronization?) + +There is a demo program called pginsert that demonstrates how the +library can be used. + +You can create a library of pginterface.c and halt.c, and just include +pginterface.h in your source code. + +I am willing to maintain this if people find problems or want additional +functionality. + +Bruce Momjian (root@candle.pha.pa.us) diff --git a/contrib/pginterface/halt.c b/contrib/pginterface/halt.c new file mode 100644 index 0000000000..58ca11a587 --- /dev/null +++ b/contrib/pginterface/halt.c @@ -0,0 +1,58 @@ +/* +** +** halt.c +** +** This is used to print out error messages and exit +*/ + +#include <varargs.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + + +/*------------------------------------------------------------------------- +** +** halt - print error message, and call clean up routine or exit +** +**------------------------------------------------------------------------*/ + +/*VARARGS*/ +void halt(va_alist) +va_dcl +{ + va_list arg_ptr; + char *format, *pstr; + void (*sig_func)(); + + va_start(arg_ptr); + format = va_arg(arg_ptr,char *); + if (strncmp(format,"PERROR", 6) != 0) + vfprintf(stderr,format,arg_ptr); + else + { + for (pstr=format+6; *pstr == ' ' || *pstr == ':'; pstr++) + ; + vfprintf(stderr,pstr,arg_ptr); + perror(""); + } + va_end(arg_ptr); + fflush(stderr); + + /* call one clean up function if defined */ + if ( (sig_func = signal(SIGTERM, SIG_DFL)) != SIG_DFL && + sig_func != SIG_IGN) + (*sig_func)(0); + else if ( (sig_func = signal(SIGHUP, SIG_DFL)) != SIG_DFL && + sig_func != SIG_IGN) + (*sig_func)(0); + else if ( (sig_func = signal(SIGINT, SIG_DFL)) != SIG_DFL && + sig_func != SIG_IGN) + (*sig_func)(0); + else if ( (sig_func = signal(SIGQUIT, SIG_DFL)) != SIG_DFL && + sig_func != SIG_IGN) + (*sig_func)(0); + exit(1); +} diff --git a/contrib/pginterface/halt.h b/contrib/pginterface/halt.h new file mode 100644 index 0000000000..cb4ea545b9 --- /dev/null +++ b/contrib/pginterface/halt.h @@ -0,0 +1,7 @@ +/* +** halt.h +** +*/ + +void halt(); + diff --git a/contrib/pginterface/pginsert.c b/contrib/pginterface/pginsert.c new file mode 100644 index 0000000000..b49d3449c6 --- /dev/null +++ b/contrib/pginterface/pginsert.c @@ -0,0 +1,98 @@ +/* + * insert.c + * +*/ + +#include <stdio.h> +#include <signal.h> +#include <time.h> +#include "halt.h" +#include <libpq-fe.h> +#include "pginterface.h" + +int main(int argc, char **argv) +{ + char query[4000]; + int row =1; + int aint; + float afloat; + double adouble; + char achar[11], achar16[17], abpchar[11], avarchar[51], atext[51]; + time_t aabstime; + + if (argc != 2) + halt("Usage: %s database\n",argv[0]); + + connectdb(argv[1],NULL,NULL,NULL,NULL); + + on_error_continue(); + doquery("DROP TABLE testfetch"); + on_error_stop(); + + doquery("\ + CREATE TABLE testfetch( \ + aint int4, \ + afloat float4, \ + adouble float8, \ + achar char, \ + achar16 char16, \ + abpchar char(10), \ + avarchar varchar(50), \ + atext text, \ + aabstime abstime) \ + "); + + while(1) + { + sprintf(query,"INSERT INTO testfetch VALUES ( \ + %d, \ + 2322.12, \ + '923121.0323'::float8, \ + 'A', \ + 'Betty', \ + 'Charley', \ + 'Doug', \ + 'Ernie', \ + 'now' )", row); + doquery(query); + + doquery("BEGIN WORK"); + doquery("DECLARE c_testfetch BINARY CURSOR FOR \ + SELECT * FROM testfetch"); + + doquery("FETCH ALL IN c_testfetch"); + + while (fetch( + &aint, + &afloat, + &adouble, + achar, + achar16, + abpchar, + avarchar, + atext, + &aabstime) != END_OF_TUPLES) + printf("int %d\nfloat %f\ndouble %f\nchar %s\nchar16 %s\n\ +bpchar %s\nvarchar %s\ntext %s\nabstime %s", + aint, + afloat, + adouble, + achar, + achar16, + abpchar, + avarchar, + atext, + ctime(&aabstime)); + + + doquery("CLOSE c_testfetch"); + doquery("COMMIT WORK"); + printf("--- %-d rows inserted so far\n",row); + + row++; + } + + disconnectdb(); + return 0; +} + diff --git a/contrib/pginterface/pginterface.c b/contrib/pginterface/pginterface.c new file mode 100644 index 0000000000..9df7021eb7 --- /dev/null +++ b/contrib/pginterface/pginterface.c @@ -0,0 +1,177 @@ +/* + * pginterface.c + * +*/ + +#include <stdio.h> +#include <signal.h> +#include <string.h> +#include <stdarg.h> + +#include "halt.h" +#include <libpq-fe.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++; +} + +/* +** +** 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); +} diff --git a/contrib/pginterface/pginterface.h b/contrib/pginterface/pginterface.h new file mode 100644 index 0000000000..6e074ff234 --- /dev/null +++ b/contrib/pginterface/pginterface.h @@ -0,0 +1,13 @@ +/* + * pglib.h + * +*/ + +PGresult *doquery(char *query); +PGconn *connectdb(); +void disconnectdb(); +int fetch(void *param, ...); +void on_error_continue(); +void on_error_stop(); + +#define END_OF_TUPLES (-1) |
