diff options
author | Bruce Momjian <bruce@momjian.us> | 2002-03-04 18:50:21 +0000 |
---|---|---|
committer | Bruce Momjian <bruce@momjian.us> | 2002-03-04 18:50:21 +0000 |
commit | b2aade0e4b43d3bddd1dfaa1a3fe0413e404afc7 (patch) | |
tree | b100fe034356f27f4e232d2c65447784483adcff /src | |
parent | e7db8fa80e58d43531469547e0f0ac1da77d3a8c (diff) | |
download | postgresql-b2aade0e4b43d3bddd1dfaa1a3fe0413e404afc7.tar.gz postgresql-b2aade0e4b43d3bddd1dfaa1a3fe0413e404afc7.zip |
Improve libpgeasy API for multiple result sets, add example.
Diffstat (limited to 'src')
-rw-r--r-- | src/interfaces/libpgeasy/examples/Makefile | 12 | ||||
-rw-r--r-- | src/interfaces/libpgeasy/libpgeasy.c | 196 |
2 files changed, 123 insertions, 85 deletions
diff --git a/src/interfaces/libpgeasy/examples/Makefile b/src/interfaces/libpgeasy/examples/Makefile index 1885bb425fb..af8dc0c32a7 100644 --- a/src/interfaces/libpgeasy/examples/Makefile +++ b/src/interfaces/libpgeasy/examples/Makefile @@ -4,23 +4,17 @@ # Makefile for pgeasy examples # # IDENTIFICATION -# $Header: /cvsroot/pgsql/src/interfaces/libpgeasy/examples/Attic/Makefile,v 1.2 2000/05/18 14:24:37 momjian Exp $ +# $Header: /cvsroot/pgsql/src/interfaces/libpgeasy/examples/Attic/Makefile,v 1.3 2002/03/04 18:50:21 momjian Exp $ # #------------------------------------------------------------------------- CFLAGS=-I/usr/local/pgsql/include -TARGET = pginsert pgwordcount pgnulltest +TARGET = pginsert pgwordcount pgnulltest pgmultiresult LDFLAGS = -L/usr/local/pgsql/lib -lpgeasy all : $(TARGET) -pginsert: - gcc -o $@ $(CFLAGS) $@.c $(PGEASY) $(LDFLAGS) - -pgwordcount: - gcc -o $@ $(CFLAGS) $@.c $(PGEASY) $(LDFLAGS) - -pgnulltest: +%: %.c gcc -o $@ $(CFLAGS) $@.c $(PGEASY) $(LDFLAGS) clean: diff --git a/src/interfaces/libpgeasy/libpgeasy.c b/src/interfaces/libpgeasy/libpgeasy.c index 4bddece659c..40684a2cfe8 100644 --- a/src/interfaces/libpgeasy/libpgeasy.c +++ b/src/interfaces/libpgeasy/libpgeasy.c @@ -6,6 +6,7 @@ #include <stdio.h> #include <string.h> #include <stdarg.h> +#include <stdlib.h> #include "libpq-fe.h" #include "halt.h" @@ -16,31 +17,33 @@ #endif #ifndef TRUE -#define TRUE 1 +#define TRUE 1 #endif #ifndef FALSE -#define FALSE 0 +#define FALSE 0 #endif /* GLOBAL VARIABLES */ static PGconn *conn; static PGresult *res = NULL; -static int tuple; /* stores fetch location */ +static int tuple; /* stores fetch location */ -#define ON_ERROR_STOP 0 -#define ON_ERROR_CONTINUE 1 +#define ON_ERROR_STOP 0 +#define ON_ERROR_CONTINUE 1 -static int on_error_state = ON_ERROR_STOP; /* halt on errors? */ +static int on_error_state = ON_ERROR_STOP; /* halt on errors? */ + +static int user_has_res = FALSE; + +static void add_res_tuple(void); +static void get_res_tuple(void); +static void del_res_tuple(void); -static int in_result_block = FALSE; -static int was_get_unset_result = FALSE; /* - * * connectdb - returns PGconn structure - * */ PGconn * connectdb(char *options) @@ -53,17 +56,14 @@ connectdb(char *options) return conn; } + /* - * * disconnectdb - * */ void disconnectdb() { - if (res != NULL && - in_result_block == FALSE && - was_get_unset_result == FALSE) + if (res != NULL && user_has_res == FALSE) { PQclear(res); res = NULL; @@ -72,20 +72,17 @@ disconnectdb() PQfinish(conn); } + /* - * * doquery - returns PGresult structure - * */ PGresult * doquery(char *query) { - if (res != NULL && - in_result_block == FALSE && - was_get_unset_result == FALSE) + if (res != NULL && user_has_res == FALSE) PQclear(res); - was_get_unset_result = FALSE; + user_has_res = FALSE; res = PQexec(conn, query); if (on_error_state == ON_ERROR_STOP && @@ -105,11 +102,10 @@ doquery(char *query) return res; } + /* - * * fetch - returns tuple number (starts at 0), or the value END_OF_TUPLES * NULL pointers are skipped - * */ int fetch(void *param,...) @@ -142,8 +138,8 @@ fetch(void *param,...) return tuple++; } + /* - * * fetchwithnulls - returns tuple number (starts at 0), * or the value END_OF_TUPLES * Returns TRUE or FALSE into null indicator variables @@ -185,10 +181,19 @@ fetchwithnulls(void *param,...) return tuple++; } + +/* + * reset_fetch + */ +void +reset_fetch() +{ + tuple = 0; +} + + /* - * * on_error_stop - * */ void on_error_stop() @@ -196,10 +201,9 @@ on_error_stop() on_error_state = ON_ERROR_STOP; } + /* - * * on_error_continue - * */ void on_error_continue() @@ -209,92 +213,132 @@ on_error_continue() /* - * * get_result - * */ PGresult * get_result() { - char *cmdstatus = PQcmdStatus(res); + if (res == NULL) + halt("get_result called with no result pointer used\n"); - was_get_unset_result = TRUE; + /* delete it if it is already there; we are about to re-add it */ + del_res_tuple(); - /* we have to store the fetch location somewhere */ - /* XXX THIS IS A NO-NO */ - cmdstatus[0] = NUL; - memcpy(&cmdstatus[1], &tuple, sizeof(tuple)); + /* we have to store the fetch location */ + add_res_tuple(); + + user_has_res = TRUE; return res; } + /* - * * set_result - * */ void set_result(PGresult *newres) { - - char *cmdstatus = PQcmdStatus(res); - if (newres == NULL) halt("set_result called with null result pointer\n"); - if (res != NULL && was_get_unset_result == FALSE) + if (res != NULL && user_has_res == FALSE) { - if (in_result_block == FALSE) - PQclear(res); - else - { - /* XXX THIS IS A NO-NO */ - cmdstatus[0] = NUL; - memcpy(&cmdstatus[1], &tuple, sizeof(tuple)); - } + /* + * Basically, throw away res. We can't return to it because the + * user doesn't have the res pointer. + */ + del_res_tuple(); + PQclear(res); } - in_result_block = TRUE; - was_get_unset_result = FALSE; - - cmdstatus = PQcmdStatus(newres); - memcpy(&tuple, &cmdstatus[1], sizeof(tuple)); + user_has_res = FALSE; res = newres; + + get_res_tuple(); } /* - * - * unset_result - * + * Routines to store res/tuple mapping + * This is used to keep track of fetch locations while using get/set on + * result sets. + * Auto-growing array is used, with empty slots marked by res == NULL */ -void -unset_result(PGresult *oldres) + +static struct res_tuple { - char *cmdstatus = PQcmdStatus(oldres); + PGresult *res; + int tuple; +} *res_tuple = NULL; - if (oldres == NULL) - halt("unset_result called with null result pointer\n"); +static int res_tuple_len = 0; - if (in_result_block == FALSE) - halt("Unset of result without being set.\n"); - was_get_unset_result = TRUE; +/* + * add_res_tuple + */ +static void +add_res_tuple(void) +{ + int i, + new_res_tuple_len = res_tuple_len ? res_tuple_len * 2 : 1; + + for (i = 0; i < res_tuple_len; i++) + /* Put it in an empty slot */ + if (res_tuple[i].res == NULL) + { + res_tuple[i].res = res; + res_tuple[i].tuple = tuple; + } + + /* Need to grow array */ + res_tuple = realloc(res_tuple, new_res_tuple_len * sizeof(struct res_tuple)); + + /* clear new elements */ + for (i = res_tuple_len; i < new_res_tuple_len; i++) + { + res_tuple[i].res = NULL; + res_tuple[i].tuple = 0; + } - /* XXX THIS IS A NO-NO */ - cmdstatus[0] = NUL; - memcpy(&cmdstatus[1], &tuple, sizeof(tuple)); - in_result_block = FALSE; + /* recursion to add entry */ + add_res_tuple(); } + /* - * - * reset_fetch - * + * get_res_tuple */ -void -reset_fetch() +static void +get_res_tuple(void) { - tuple = 0; + int i; + + for (i = 0; i < res_tuple_len; i++) + if (res_tuple[i].res == res) + { + tuple = res_tuple[i].tuple; + return; + } + halt("get_res_tuple called with invalid result pointer\n"); +} + + +/* + * del_res_tuple + */ +static void +del_res_tuple(void) +{ + int i; + + for (i = 0; i < res_tuple_len; i++) + if (res_tuple[i].res == res) + { + res_tuple[i].res = NULL; + return; + } + return; } |