From: Marc G. Fournier Date: Thu, 13 Feb 1997 10:01:05 +0000 (+0000) Subject: Bring in Leo's massive changes to libpq++ X-Git-Tag: REL6_1~558 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=eacd0fd938663b8c673d8e3ac9549c9f3b7b463d;p=postgresql Bring in Leo's massive changes to libpq++ --- diff --git a/src/interfaces/libpq++/Makefile b/src/interfaces/libpq++/Makefile index 941c07da4f..7707c186a3 100644 --- a/src/interfaces/libpq++/Makefile +++ b/src/interfaces/libpq++/Makefile @@ -7,12 +7,16 @@ # # # IDENTIFICATION -# $Header: /cvsroot/pgsql/src/interfaces/libpq++/Attic/Makefile,v 1.5 1996/11/18 01:43:54 bryanh Exp $ +# $Header: /cvsroot/pgsql/src/interfaces/libpq++/Attic/Makefile,v 1.6 1997/02/13 10:00:23 scrappy Exp $ # #------------------------------------------------------------------------- SRCDIR= .. include ../Makefile.global +SRCHEADERDIR = ../include +LIBPQHEADERDIR = $(SRCHEADERDIR)/libpq + +LIBNAME= libpq++ # We have to override -Werror, which makes warnings, fatal, because we # inevitably get the warning, "abstract declarator used as declaration" @@ -22,48 +26,72 @@ CXXFLAGS= $(CFLAGS) -Wno-error INCLUDE_OPT= \ -I../backend \ - -I../include \ - -I$(LIBPQDIR) + -I$(SRCHEADERDIR) \ + -I$(LIBPQDIR) CXXFLAGS+= $(INCLUDE_OPT) +#CXXFLAGS+= -DDEBUG ifdef KRBVERS CXXFLAGS+= $(KRBFLAGS) endif -OBJS= pgenv.o pgconnection.o pglobject.o -all: libpq++.a examples +OBJS = pgenv.o pgconnection.o pgtransdb.o pgcursordb.o pglobject.o + +all: $(LIBNAME).a install examples -libpq++.a: $(OBJS) +$(LIBNAME).a: $(OBJS) ifdef MK_NO_LORDER - $(AR) $(AROPT) libpq++.a $(OBJS) + $(AR) $(AROPT) $(LIBNAME).a $(OBJS) else - $(AR) $(AROPT) libpq++.a `lorder $(OBJS) | tsort` + $(AR) $(AROPT) $(LIBNAME).a `lorder $(OBJS) | tsort` endif - $(RANLIB) libpq++.a + $(RANLIB) $(LIBNAME).a .PHONY: examples examples: $(MAKE) -C examples all .PHONY: beforeinstall-headers install-headers -.PHONY: install install-libpq++ doc - -install: install-headers install-libpq++ doc - -install-headers: beforeinstall-headers libpq++.H - $(INSTALL) $(INSTLOPTS) libpq++.H $(HEADERDIR)/libpq++.H +.PHONY: install install-$(LIBNAME) doc + +install: install-headers install-$(LIBNAME) doc + +LIBPGXXDIR = $(LIBNAME) +LIBPGXXHEADERDIR = $(HEADERDIR)/$(LIBPGXXDIR) +MAINHEADER = $(LIBNAME).h +LIBPGXXHEADERS = pgenv.h \ + pgconnection.h \ + pgdatabase.h \ + pgtransdb.h \ + pgcursordb.h \ + pglobject.h + +install-headers: beforeinstall-headers $(MAINHEADER) + @$(INSTALL) $(INSTLOPTS) $(MAINHEADER) $(HEADERDIR)/$(MAINHEADER) + @for i in ${LIBPGXXHEADERS}; do \ + echo "Installing $(LIBPGXXHEADERDIR)/$$i."; \ + $(INSTALL) $(INSTLOPTS) $$i $(LIBPGXXHEADERDIR)/$$i; \ + done beforeinstall-headers: @if [ ! -d $(HEADERDIR) ]; then mkdir $(HEADERDIR); fi + @if [ ! -d $(LIBPGXXHEADERDIR) ]; then mkdir $(LIBPGXXHEADERDIR); fi -install-libpq++: libpq++.a - $(INSTALL) $(INSTL_LIB_OPTS) libpq++.a $(DESTDIR)$(LIBDIR)/libpq++.a +install-$(LIBNAME): $(LIBNAME).a + $(INSTALL) $(INSTL_LIB_OPTS) $(LIBNAME).a $(DESTDIR)$(LIBDIR)/$(LIBNAME).a doc: $(MAKE) -C man install clean: - rm libpq++.a $(OBJS) + rm $(LIBNAME).a $(OBJS) $(MAKE) -C examples clean + + +########################################################################### +# Dependencies for the library +########################################################################### +include ./dependencies + diff --git a/src/interfaces/libpq++/dependencies b/src/interfaces/libpq++/dependencies new file mode 100644 index 0000000000..89633e1e87 --- /dev/null +++ b/src/interfaces/libpq++/dependencies @@ -0,0 +1,36 @@ +########################################################################### +# Dependencies for libpq++ C++ library for Postgres SQL +# +# Author: Leo Shuster (lsh@lubrizol.com) +########################################################################### +pgenv.o :: pgenv.cc \ + pgenv.h + +pgconnection.o :: pgconnection.cc \ + pgconnection.h \ + pgenv.h \ + $(LIBPQDIR)/libpq-fe.h \ + $(LIBPQDIR)/fe-auth.h + +pgtransdb.o :: pgtransdb.cc \ + pgtransdb.h \ + pgdatabase.h \ + pgconnection.h \ + pgenv.h \ + $(LIBPQDIR)/libpq-fe.h \ + $(LIBPQDIR)/fe-auth.h + +pgcursordb.o :: pgcursordb.cc \ + pgcursordb.h \ + pgdatabase.h \ + pgconnection.h \ + pgenv.h \ + $(LIBPQDIR)/libpq-fe.h \ + $(LIBPQDIR)/fe-auth.h + +pglobject.o :: pglobject.cc \ + pglobject.h \ + pgconnection.h \ + pgenv.h \ + $(LIBPQDIR)/libpq-fe.h \ + $(LIBPQHEADERDIR)/libpq-fs.h diff --git a/src/interfaces/libpq++/examples/Makefile b/src/interfaces/libpq++/examples/Makefile index 21e0f38b7c..c08806002b 100644 --- a/src/interfaces/libpq++/examples/Makefile +++ b/src/interfaces/libpq++/examples/Makefile @@ -5,6 +5,8 @@ SRCDIR= ../.. include ../../Makefile.global +LIBNAME= libpq++ + # We have to override -Werror, which makes warnings, fatal, because we # inevitably get the warning, "abstract declarator used as declaration" # because of our inclusion of c.h and we don't know how to stop that. @@ -15,8 +17,8 @@ INCLUDE_OPT= \ -I.. \ -I../../backend \ -I../../include \ - -I$(LIBPQDIR) - + -I$(LIBPQDIR) \ + -I$(HEADERDIR) CXXFLAGS+= $(INCLUDE_OPT) LD_ADD+= -L.. -lpq++ -L$(LIBPQDIR) -lpq @@ -29,19 +31,21 @@ LD_ADD+= $(KRBLIBS) CXXFLAGS+= $(KRBFLAGS) endif -PROGS= testlibpq0 testlibpq1 testlibpq2 testlibpq3 testlibpq4 testlo +PROGS= testlibpq0 testlibpq1 testlibpq2 testlibpq3 \ + testlibpq4 testlibpq5 testlibpq6 testlo all: submake $(PROGS) -$(PROGS): % : %.cc ../libpq++.a +$(PROGS): % : %.cc ../$(LIBNAME).a $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ $@.cc $(LD_ADD) .PHONY: submake submake: - $(MAKE) -C.. libpq++.a + $(MAKE) -C.. $(LIBNAME).a -../libpq++.a: - $(MAKE) -C.. libpq++.a +../$(LIBNAME).a: + $(MAKE) -C.. $(LIBNAME).a clean: rm -f $(PROGS) + diff --git a/src/interfaces/libpq++/examples/testlibpq0.cc b/src/interfaces/libpq++/examples/testlibpq0.cc index e8adb21f1b..43f8e93d15 100644 --- a/src/interfaces/libpq++/examples/testlibpq0.cc +++ b/src/interfaces/libpq++/examples/testlibpq0.cc @@ -9,41 +9,44 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/interfaces/libpq++/examples/Attic/testlibpq0.cc,v 1.2 1996/11/18 01:44:23 bryanh Exp $ + * $Header: /cvsroot/pgsql/src/interfaces/libpq++/examples/Attic/testlibpq0.cc,v 1.3 1997/02/13 10:00:42 scrappy Exp $ * *------------------------------------------------------------------------- */ -#include -#include "libpq++.H" +#include +#include -int -main() +int main() { + // Open the connection to the database and make sure it's OK + PgDatabase data("template1"); + if ( data.ConnectionBad() ) { + cout << "Connection was unsuccessful..." << endl + << "Error message returned: " << data.ErrorMessage() << endl; + return 1; + } + else + cout << "Connection successful... Enter queries below:" << endl; + + // Interactively obtain and execute queries ExecStatusType status; - PGenv env; - PGdatabase* data; - - char buf[10000]; + string buf; int done = 0; - - data = new PGdatabase(&env, "template1"); - - if (data->status() == CONNECTION_BAD) - printf("connection was unsuccessful\n%s\n", data->errormessage()); - else - printf("connection successful\n"); - while (!done) { - printf("> ");fflush(stdout); - if (gets(buf) && buf[0]!='\0') - if((status = data->exec(buf)) == PGRES_TUPLES_OK) - data->printtuples(stdout, 1, "|", 1, 0); - else - printf("status = %d\nerrorMessage = %s\n", status, - data->errormessage()); + cout << "> "; + cout.flush(); + getline(cin, buf); + if ( buf != "" ) + if ( (status = data.Exec( buf.c_str() )) == PGRES_TUPLES_OK ) + data.DisplayTuples(); + else + cout << "No tuples returned..." << endl + << "status = " << status << endl + << "Error returned: " << data.ErrorMessage() << endl; else - done = 1; - } -} + done = 1; + } + return 0; +} // End main() diff --git a/src/interfaces/libpq++/examples/testlibpq1.cc b/src/interfaces/libpq++/examples/testlibpq1.cc index 1d71f79558..ef63cf7077 100644 --- a/src/interfaces/libpq++/examples/testlibpq1.cc +++ b/src/interfaces/libpq++/examples/testlibpq1.cc @@ -1,84 +1,67 @@ /* - * testlibpq.cc + * testlibpq1.cc * Test the C++ version of LIBPQ, the POSTGRES frontend library. * * queries the template1 database for a list of database names * */ -#include -#include "libpq++.H" -main() -{ - char* dbName; - int nFields; - int i,j; - - /* begin, by creating the parameter environtment for a backend - connection. When no parameters are given then the system will - try to use reasonable defaults by looking up environment variables - or, failing that, using hardwired constants */ - PGenv env; - PGdatabase* data; +#include +#include +#include - /* Select a database */ - dbName = "template1"; - - /* make a connection to the database */ - data = new PGdatabase(&env, dbName); +int main() +{ + // Begin, by establishing a connection to the backend. + // When no parameters are given then the system will + // try to use reasonable defaults by looking up environment variables + // or, failing that, using hardwired constants + const char* dbName = "template1"; + PgDatabase data(dbName); - /* check to see that the backend connection was successfully made */ - if (data->status() == CONNECTION_BAD) { - fprintf(stderr,"Connection to database '%s' failed.\n", dbName); - fprintf(stderr,"%s",data->errormessage()); - delete data; - exit(1); + // check to see that the backend connection was successfully made + if ( data.ConnectionBad() ) { + cerr << "Connection to database '" << dbName << "' failed." << endl + << "Error returned: " << data.ErrorMessage() << endl; + exit(1); } - /* start a transaction block */ - if(data->exec("BEGIN") != PGRES_COMMAND_OK) { - fprintf(stderr,"BEGIN command failed\n"); - delete data; + // start a transaction block + if ( !data.ExecCommandOk("BEGIN") ) { + cerr << "BEGIN command failed" << endl; exit(1); } - /* fetch instances from the pg_database, the system catalog of databases*/ - if (data->exec("DECLARE myportal CURSOR FOR select * from pg_database") - != PGRES_COMMAND_OK) { - fprintf(stderr,"DECLARE CURSOR command failed\n"); - delete data; + // submit command to the backend + if ( !data.ExecCommandOk("DECLARE myportal CURSOR FOR select * from pg_database") ) { + cerr << "DECLARE CURSOR command failed" << endl; exit(1); } - if(data->exec("FETCH ALL in myportal") != PGRES_TUPLES_OK) { - fprintf(stderr,"FETCH ALL command didn't return tuples properly\n"); - delete data; + // fetch instances from the pg_database, the system catalog of databases + if ( !data.ExecTuplesOk("FETCH ALL in myportal") ) { + cerr << "FETCH ALL command didn't return tuples properly" << endl; exit(1); } - /* first, print out the attribute names */ - nFields = data->nfields(); - for (i=0; i < nFields; i++) { - printf("%-15s",data->fieldname(i)); - } - printf("\n\n"); + // first, print out the attribute names + int nFields = data.Fields(); + for (int i=0; i < nFields; i++) + cout << setiosflags(ios::right) << setw(15) << data.FieldName(i); + cout << endl << endl; - /* next, print out the instances */ - for (i=0; i < data->ntuples(); i++) { - for (j=0 ; j < nFields; j++) { - printf("%-15s", data->getvalue(i,j)); - } - printf("\n"); + // next, print out the instances + for (int i=0; i < data.Tuples(); i++) { + for (int j=0; j < nFields; j++) + cout << setiosflags(ios::right) << setw(15) << data.GetValue(i,j); + cout << endl; } - /* close the portal */ - data->exec("CLOSE myportal"); - - /* end the transaction */ - data->exec("END"); + // Close the portal + data.Exec("CLOSE myportal"); - /* close the connection to the database and cleanup */ - delete data; + // End the transaction + data.Exec("END"); } diff --git a/src/interfaces/libpq++/examples/testlibpq2.cc b/src/interfaces/libpq++/examples/testlibpq2.cc index 5acba9666c..c6f6215bbc 100644 --- a/src/interfaces/libpq++/examples/testlibpq2.cc +++ b/src/interfaces/libpq++/examples/testlibpq2.cc @@ -1,69 +1,56 @@ /* * testlibpq2.cc - * Test of the asynchronous notification interface - * - populate a database with the following: - -CREATE TABLE TBL1 (i int4); - -CREATE TABLE TBL2 (i int4); - -CREATE RULE r1 AS ON INSERT TO TBL1 DO [INSERT INTO TBL2 values (new.i); NOTIFY TBL2]; - - * Then start up this program - * After the program has begun, do - -INSERT INTO TBL1 values (10); - + * Test the C++ version of LIBPQ, the POSTGRES frontend library. * + * queries the template1 database for a list of database names using transaction block * */ -#include -#include "libpq++.H" -main() -{ - char* dbName; - - /* begin, by creating the parameter environtment for a backend - connection. When no parameters are given then the system will - try to use reasonable defaults by looking up environment variables - or, failing that, using hardwired constants */ - PGenv env; - PGdatabase* data; - PGnotify* notify; +#include +#include +#include - dbName = getenv("USER"); /* change this to the name of your test database */ - - /* make a connection to the database */ - data = new PGdatabase(&env, dbName); +int main() +{ + // Begin, by establishing a connection to the backend. + // When no parameters are given then the system will + // try to use reasonable defaults by looking up environment variables + // or, failing that, using hardwired constants + const char* dbName = "template1"; + PgTransaction data(dbName); + + // check to see that the backend connection was successfully made + if ( data.ConnectionBad() ) { + cerr << "Connection to database '" << dbName << "' failed." << endl + << "Error returned: " << data.ErrorMessage() << endl; + exit(1); + } - /* check to see that the backend connection was successfully made */ - if (data->status() == CONNECTION_BAD) { - fprintf(stderr,"Connection to database '%s' failed.\n", dbName); - fprintf(stderr,"%s",data->errormessage()); - delete data; + // submit command to the backend + if ( !data.ExecCommandOk("DECLARE myportal CURSOR FOR select * from pg_database") ) { + cerr << "DECLARE CURSOR command failed" << endl; exit(1); } - if (data->exec("LISTEN TBL2") != PGRES_COMMAND_OK) { - fprintf(stderr,"LISTEN command failed\n"); - delete data; + // fetch instances from the pg_database, the system catalog of databases + if ( !data.ExecTuplesOk("FETCH ALL in myportal") ) { + cerr << "FETCH ALL command didn't return tuples properly" << endl; exit(1); } - - while (1) { - /* check for asynchronous returns */ - notify = data->notifies(); - if (notify) { - fprintf(stderr, - "ASYNC NOTIFY of '%s' from backend pid '%d' received\n", - notify->relname, notify->be_pid); - free(notify); - break; - } + + // first, print out the attribute names + int nFields = data.Fields(); + for (int i=0; i < nFields; i++) + cout << setiosflags(ios::right) << setw(15) << data.FieldName(i); + cout << endl << endl; + + // next, print out the instances + for (int i=0; i < data.Tuples(); i++) { + for (int j=0; j < nFields; j++) + cout << setiosflags(ios::right) << setw(15) << data.GetValue(i,j); + cout << endl; } - - /* close the connection to the database and cleanup */ - delete data; + + // close the portal + data.Exec("CLOSE myportal"); } diff --git a/src/interfaces/libpq++/examples/testlibpq3.cc b/src/interfaces/libpq++/examples/testlibpq3.cc index b1e94e487e..3c4e6ec429 100644 --- a/src/interfaces/libpq++/examples/testlibpq3.cc +++ b/src/interfaces/libpq++/examples/testlibpq3.cc @@ -1,130 +1,56 @@ /* * testlibpq3.cc * Test the C++ version of LIBPQ, the POSTGRES frontend library. - * tests the binary cursor interface * - * - * - populate a database by doing the following: - -CREATE TABLE test1 (i int4, d float4, p polygon); - -INSERT INTO test1 values (1, 3.567, '(3.0, 4.0, 1.0, 2.0)'::polygon); - -INSERT INTO test1 values (2, 89.05, '(4.0, 3.0, 2.0, 1.0)'::polygon); - - the expected output is: - -tuple 0: got - i = (4 bytes) 1, - d = (4 bytes) 3.567000, - p = (4 bytes) 2 points boundbox = (hi=3.000000/4.000000, lo = 1.000000,2.000000) -tuple 1: got - i = (4 bytes) 2, - d = (4 bytes) 89.050003, - p = (4 bytes) 2 points boundbox = (hi=4.000000/3.000000, lo = 2.000000,1.000000) - + * queries the template1 database for a list of database names using transaction block + * and cursor interface. * */ -#include -#include "libpq++.H" -extern "C" { -#include "utils/geo-decls.h" /* for the POLYGON type */ -} - -main() -{ - char* dbName; - int i_fnum, d_fnum, p_fnum; - int i; - - /* begin, by creating the parameter environtment for a backend - connection. When no parameters are given then the system will - try to use reasonable defaults by looking up environment variables - or, failing that, using hardwired constants */ - PGenv env; - PGdatabase* data; - - dbName = getenv("USER"); /* change this to the name of your test database */ - - /* make a connection to the database */ - data = new PGdatabase(&env, dbName); - /* check to see that the backend connection was successfully made */ - if (data->status() == CONNECTION_BAD) { - fprintf(stderr,"Connection to database '%s' failed.\n", dbName); - fprintf(stderr,"%s",data->errormessage()); - delete data; - exit(1); - } +#include +#include +#include - /* start a transaction block */ - if (data->exec("BEGIN") != PGRES_COMMAND_OK) { - fprintf(stderr,"BEGIN command failed\n"); - delete data; - exit(1); +int main() +{ + // Begin, by establishing a connection to the backend. + // When no parameters are given then the system will + // try to use reasonable defaults by looking up environment variables + // or, failing that, using hardwired constants. + // Create a cursor database query object. + // All queries using cursor will be performed through this object. + const char* dbName = "template1"; + PgCursor cData(dbName, "myportal"); + + // check to see that the backend connection was successfully made + if ( cData.ConnectionBad() ) { + cerr << "Connection to database '" << dbName << "' failed." << endl + << "Error returned: " << cData.ErrorMessage() << endl; + exit(1); } - - /* fetch instances from the pg_database, the system catalog of databases*/ - if (data->exec("DECLARE mycursor BINARY CURSOR FOR select * from test1") - != PGRES_COMMAND_OK) { - fprintf(stderr,"DECLARE CURSOR command failed\n"); - delete data; + + // submit command to the backend + if ( !cData.Declare("select * from pg_database") ) { + cerr << "DECLARE CURSOR command failed" << endl; exit(1); } - if (data->exec("FETCH ALL in mycursor") != PGRES_TUPLES_OK) { - fprintf(stderr,"FETCH ALL command didn't return tuples properly\n"); - delete data; + // fetch instances from the pg_cDatabase, the system catalog of cDatabases + if ( !cData.Fetch() ) { + cerr << "FETCH ALL command didn't return tuples properly" << endl; exit(1); } - i_fnum = data->fieldnum("i"); - d_fnum = data->fieldnum("d"); - p_fnum = data->fieldnum("p"); - -/* - for (i=0;i<3;i++) { - printf("type[%d] = %d, size[%d] = %d\n", - i, data->fieldtype(i), - i, data->fieldsize(i)); - } -*/ - - for (i=0; i < data->ntuples(); i++) { - int *ival; - float *dval; - int plen; - POLYGON* pval; - /* we hard-wire this to the 3 fields we know about */ - ival = (int*)data->getvalue(i,i_fnum); - dval = (float*)data->getvalue(i,d_fnum); - plen = data->getlength(i,p_fnum); - - /* plen doesn't include the length field so need to increment by VARHDSZ*/ - pval = (POLYGON*) malloc(plen + VARHDRSZ); - pval->size = plen; - memmove((char*)&pval->npts, data->getvalue(i,p_fnum), plen); - printf("tuple %d: got\n", i); - printf(" i = (%d bytes) %d,\n", - data->getlength(i,i_fnum), *ival); - printf(" d = (%d bytes) %f,\n", - data->getlength(i,d_fnum), *dval); - printf(" p = (%d bytes) %d points \tboundbox = (hi=%f/%f, lo = %f,%f)\n", - data->getlength(i,d_fnum), - pval->npts, - pval->boundbox.xh, - pval->boundbox.yh, - pval->boundbox.xl, - pval->boundbox.yl); + // first, print out the attribute names + int nFields = cData.Fields(); + for (int i=0; i < nFields; i++) + cout << setiosflags(ios::right) << setw(15) << cData.FieldName(i); + cout << endl << endl; + + // next, print out the instances + for (int i=0; i < cData.Tuples(); i++) { + for (int j=0; j < nFields; j++) + cout << setiosflags(ios::right) << setw(15) << cData.GetValue(i,j); + cout << endl; } - - /* close the portal */ - data->exec("CLOSE mycursor"); - - /* end the transaction */ - data->exec("END"); - - /* close the connection to the database and cleanup */ - delete data; } diff --git a/src/interfaces/libpq++/examples/testlibpq4.cc b/src/interfaces/libpq++/examples/testlibpq4.cc index dc78031843..a1b21d33a9 100644 --- a/src/interfaces/libpq++/examples/testlibpq4.cc +++ b/src/interfaces/libpq++/examples/testlibpq4.cc @@ -1,66 +1,58 @@ /* * testlibpq4.cc - * Test the C++ version of LIBPQ, the POSTGRES frontend library. - * tests the copy in features + * Test of the asynchronous notification interface * - */ -#include -#include "libpq++.H" + populate a test database with the following (use testlibpq4.sql): -main() -{ - char* dbName; +CREATE TABLE TBL1 (i int4); - /* begin, by creating the parameter environment for a backend - connection. When no parameters are given then the system will - try to use reasonable defaults by looking up environment variables - or, failing that, using hardwired constants */ - PGenv env; - PGdatabase* data; +CREATE TABLE TBL2 (i int4); - dbName = getenv("USER"); /* change this to the name of your test database */ +CREATE RULE r1 AS ON INSERT TO TBL1 DO [INSERT INTO TBL2 values (new.i); NOTIFY TBL2]; - /* make a connection to the database */ - data = new PGdatabase(&env, dbName); + * Then start up this program + * After the program has begun, do - /* check to see that the backend connection was successfully made */ - if (data->status() == CONNECTION_BAD) { - fprintf(stderr,"Connection to database '%s' failed.\n", dbName); - fprintf(stderr,"%s",data->errormessage()); - delete data; - exit(1); - } +INSERT INTO TBL1 values (10); + + * + * + */ +#include +#include +#include - /* start a transaction block */ - if(data->exec("BEGIN") != PGRES_COMMAND_OK) { - fprintf(stderr,"BEGIN command failed\n"); - delete data; +main() +{ + // Begin, by connecting to the backend using hardwired constants + // and a test database created by the user prior to the invokation + // of this test program. + char* dbName = getenv("USER"); // change this to the name of your test database + PgDatabase data(dbName); + + // Check to see that the backend connection was successfully made + if ( data.ConnectionBad() ) { + cerr << "Connection to database '" << dbName << "' failed." << endl + << data.ErrorMessage() << endl; exit(1); } - if (data->exec("CREATE TABLE foo (a int4, b char16, d float8)") != - PGRES_COMMAND_OK) { - fprintf(stderr,"CREATE TABLE foo command failed\n"); - delete data; - exit(1); + // Listen to a table + if ( !data.ExecCommandOk("LISTEN TBL2") ) { + cerr << "LISTEN command failed" << endl; + exit(1); } - if (data->exec("COPY foo FROM STDIN") != PGRES_COMMAND_OK) { - fprintf(stderr,"COPY foo FROM STDIN\n"); - delete data; - exit(1); + // Test asynchronous notification + while (1) { + // check for asynchronous returns + PGnotify* notify = data.Notifies(); + if (notify) { + cerr << "ASYNC NOTIFY of '" << notify->relname + << "' from backend pid '" << notify->be_pid + << "' received" << endl; + free(notify); + break; + } } - - data->putline("3\thello world\t4.5\n"); - data->putline("4\tgoodbye word\t7.11\n"); - data->putline(".\n"); - data->endcopy(); - data->exec("SELECT * FROM foo"); - data->printtuples(stdout,1,"|",1,0); - data->exec("DROP TABLE foo"); - // end the transaction - data->exec("END"); - - // close the connection to the database and cleanup - delete data; } diff --git a/src/interfaces/libpq++/examples/testlibpq4.sql b/src/interfaces/libpq++/examples/testlibpq4.sql new file mode 100644 index 0000000000..f9c7410932 --- /dev/null +++ b/src/interfaces/libpq++/examples/testlibpq4.sql @@ -0,0 +1,5 @@ +CREATE TABLE TBL1 (i int4); + +CREATE TABLE TBL2 (i int4); + +CREATE RULE r1 AS ON INSERT TO TBL1 DO [INSERT INTO TBL2 values (new.i); NOTIFY TBL2]; diff --git a/src/interfaces/libpq++/examples/testlibpq5.cc b/src/interfaces/libpq++/examples/testlibpq5.cc new file mode 100644 index 0000000000..8c299fe73b --- /dev/null +++ b/src/interfaces/libpq++/examples/testlibpq5.cc @@ -0,0 +1,102 @@ +/* + * testlibpq5.cc + * Test the C++ version of LIBPQ, the POSTGRES frontend library. + * tests the binary cursor interface + * + * + * + populate a database by doing the following (use testlibpq5.sql): + +CREATE TABLE test1 (i int4, d float4, p polygon); + +INSERT INTO test1 values (1, 3.567, '(3.0, 4.0, 1.0, 2.0)'::polygon); + +INSERT INTO test1 values (2, 89.05, '(4.0, 3.0, 2.0, 1.0)'::polygon); + + the expected output is: + +tuple 0: got + i = (4 bytes) 1, + d = (4 bytes) 3.567000, + p = (4 bytes) 2 points boundbox = (hi=3.000000/4.000000, lo = 1.000000,2.000000) +tuple 1: got + i = (4 bytes) 2, + d = (4 bytes) 89.050003, + p = (4 bytes) 2 points boundbox = (hi=4.000000/3.000000, lo = 2.000000,1.000000) + + * + */ +#include +#include +#include +extern "C" { +#include "postgres.h" // for Postgres types +#include "utils/geo-decls.h" // for the POLYGON type +} + +main() +{ + // Begin, by connecting to the backend using hardwired constants + // and a test database created by the user prior to the invokation + // of this test program. Connect using cursor interface. + char* dbName = getenv("USER"); // change this to the name of your test database + PgCursor data(dbName, "mycursor"); + + // check to see that the backend connection was successfully made + if ( data.ConnectionBad() ) { + cerr << "Connection to database '" << dbName << "' failed." << endl + << data.ErrorMessage(); + exit(1); + } + + // Declare a binary cursor for all the tuples in database 'test1' + if ( !data.Declare("select * from test1", 1) ) { + cerr << "DECLARE CURSOR command failed" << endl; + exit(1); + } + + // fetch all instances from the current cursor + if ( !data.Fetch() ) { + cerr << "FETCH ALL command didn't return tuples properly" << endl; + exit(1); + } + + // Find the field numbers for the columns 'i', 'd', and 'p' + int i_fnum = data.FieldNum("i"); + int d_fnum = data.FieldNum("d"); + int p_fnum = data.FieldNum("p"); + +/* + for (i=0;i<3;i++) { + printf("type[%d] = %d, size[%d] = %d\n", + i, data.FieldType(i), + i, data.FieldSize(i)); + } +*/ + + // Print out the information about the extracted tuple + for (int i=0; i < data.Tuples(); i++) { + // we hard-wire this to the 3 fields we know about + int* ival = (int*)data.GetValue(i,i_fnum); + float* dval = (float*)data.GetValue(i,d_fnum); + int plen = data.GetLength(i,p_fnum); + + // Allocate correct memory space for the Polygon struct and copy + // the extracted data into it. + // plen doesn't include the length field so need to increment by VARHDSZ + POLYGON* pval = (POLYGON*) malloc(plen + VARHDRSZ); + pval->size = plen; + memmove((char*)&pval->npts, data.GetValue(i,p_fnum), plen); + + // Display Polygon Information + cout << "tuple " << i << ": got" << endl + << " i = (" << data.GetLength(i,i_fnum) << " bytes) " << *ival << "," << endl + << " d = (" << data.GetLength(i,d_fnum) << " bytes) " << *dval << "," << endl + << " p = (" << data.GetLength(i,d_fnum) << " bytes) " << pval->npts << " points" + << "\tboundbox = (hi=" << pval->boundbox.xh << "/" << pval->boundbox.yh << "," + << "lo = " << pval->boundbox.xl << "," << pval->boundbox.yl << ")" << endl; + + // Deallocate memory allocated for the Polygon structure + free(pval); + } +} diff --git a/src/interfaces/libpq++/examples/testlibpq5.sql b/src/interfaces/libpq++/examples/testlibpq5.sql new file mode 100644 index 0000000000..f024c0b071 --- /dev/null +++ b/src/interfaces/libpq++/examples/testlibpq5.sql @@ -0,0 +1,6 @@ +CREATE TABLE test1 (i int4, d float4, p polygon); + +INSERT INTO test1 values (1, 3.567, '(3.0, 4.0, 1.0, 2.0)'::polygon); + +INSERT INTO test1 values (2, 89.05, '(4.0, 3.0, 2.0, 1.0)'::polygon); + diff --git a/src/interfaces/libpq++/examples/testlibpq6.cc b/src/interfaces/libpq++/examples/testlibpq6.cc new file mode 100644 index 0000000000..bbf1043a0b --- /dev/null +++ b/src/interfaces/libpq++/examples/testlibpq6.cc @@ -0,0 +1,59 @@ +/* + * testlibpq4.cc + * Test the C++ version of LIBPQ, the POSTGRES frontend library. + * tests the copy in features + * + */ +#include +#include +#include + +main() +{ + // Begin, by connecting to the backend using hardwired constants + // and a test database created by the user prior to the invokation + // of this test program. Connect using transaction interface. + char* dbName = getenv("USER"); // change this to the name of your test database + PgTransaction data(dbName); + + // check to see that the backend connection was successfully made + if ( data.ConnectionBad() ) { + cerr << "Connection to database '" << dbName << "' failed." << endl + << data.ErrorMessage(); + exit(1); + } + else cout << "Connected to database '" << dbName << "'..." << endl; + + // Create a new table + if ( !data.ExecCommandOk("CREATE TABLE foo (a int4, b char16, d float8)") ) { + cerr << "CREATE TABLE foo command failed" << endl; + exit(1); + } + else cout << "CREATEd TABLE foo successfully.." << endl; + + // Initiate Copy command + if ( data.ExecCommandOk("COPY foo FROM STDIN") ) { + cerr << "COPY foo FROM STDIN" << endl; + exit(1); + } + else cout << "COPY foo FROM STDIN was successful.." << endl; + + // Put some test data into the table + data.PutLine("3\thello world\t4.5\n"); + cout << "Line: \"3\thello world\t4.5\" copied..." << endl; + data.PutLine("4\tgoodbye word\t7.11\n"); + cout << "Line: \"4\tgoodbye word\t7.11\" copied..." << endl; + data.PutLine(".\n"); + cout << "Line: \".\" copied..." << endl; + if ( !data.EndCopy() ) + cout << "Ended COPY succesfully..." << endl; + else cerr << "End Copy failed..." << endl; + + // Print the data that was inserted into the table + if ( data.ExecTuplesOk("SELECT * FROM foo") ) + data.PrintTuples(); + else cerr << "SELECT * FROM foo failed..." << endl; + + // Drop the test table + data.Exec("DROP TABLE foo"); +} diff --git a/src/interfaces/libpq++/examples/testlo.cc b/src/interfaces/libpq++/examples/testlo.cc index 8e9b4757df..df1dc6c360 100644 --- a/src/interfaces/libpq++/examples/testlo.cc +++ b/src/interfaces/libpq++/examples/testlo.cc @@ -7,56 +7,43 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/interfaces/libpq++/examples/Attic/testlo.cc,v 1.2 1996/11/18 01:44:28 bryanh Exp $ + * $Header: /cvsroot/pgsql/src/interfaces/libpq++/examples/Attic/testlo.cc,v 1.3 1997/02/13 10:01:05 scrappy Exp $ * *------------------------------------------------------------------------- */ -#include -#include "libpq++.H" -extern "C" { -#include "libpq/libpq-fs.h" -} +#include +#include +#include -int -main(int argc, char **argv) +int main(int argc, char **argv) { - char *in_filename, *out_filename; - char *database; - PGenv env; - PGlobj *object; - + // Check if the program was invoked correctly; if not, signal error if (argc < 4 || argc > 5) { - fprintf(stderr, "Usage: %s database_name in_filename out_filename [oid]\n", - argv[0]); + cerr << "Usage: " << argv[0] << " database_name in_filename out_filename [oid]" << endl; exit(1); } - database = argv[1]; - in_filename = argv[2]; - out_filename = argv[3]; + // Get the arguments passed to the program + char* database = argv[1]; + char* in_filename = argv[2]; + char* out_filename = argv[3]; - /* - * set up the connection and create a largeobject for us - */ - if (argc == 4) { - object = new PGlobj(&env, database); - } else { - object = new PGlobj(&env, database, atoi(argv[4])); - } + // Set up the connection and create a large object + int lobjId = ( argc == 4 ? 0 : atoi(argv[4]) ); + PgLargeObject object(lobjId, database); - /* check to see that the backend connection was successfully made */ - if (object->status() == CONNECTION_BAD) { - fprintf(stderr,"Connection to database '%s' failed.\n", database); - fprintf(stderr,"%s",object->errormessage()); - delete object; - exit(1); + // check to see that the backend connection was successfully made + if ( object.ConnectionBad() ) { + cerr << "Connection to database '" << database << "' failed." << endl + << object.ErrorMessage(); + exit(1); } - - object->exec("BEGIN"); - printf("importing file \"%s\" ...\n", in_filename); - object->import(in_filename); - printf("exporting large object to file \"%s\" ...\n", out_filename); - object->export(out_filename); - object->exec("END"); // WHY DOES IT CORE DUMP HERE ??? - delete object; + + // Test the import and export features of the Large Object interface + object.Exec("BEGIN"); + cout << "Importing file \"" << in_filename << "\"..." << endl; + object.Import(in_filename); + cout << "Exporting large object to file \"" << out_filename << "\"..." << endl; + object.Export(out_filename); + object.Exec("END"); // WHY DOES IT CORE DUMP HERE ??? } diff --git a/src/interfaces/libpq++/libpq++.h b/src/interfaces/libpq++/libpq++.h new file mode 100644 index 0000000000..ee257bf6f7 --- /dev/null +++ b/src/interfaces/libpq++/libpq++.h @@ -0,0 +1,33 @@ +/*------------------------------------------------------------------------- + * + * libpq++.H + * + * + * DESCRIPTION + * C++ client interface to Postgres + * used for building front-end applications + * + * NOTES + * Currently under construction. + * + * Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * + * $Id: libpq++.h,v 1.1 1997/02/13 10:00:25 scrappy Exp $ + * + *------------------------------------------------------------------------- + */ + +#ifndef LIBPQXX_H +#define LIBPQXX_H + +#include "libpq++/pgenv.h" +#include "libpq++/pgconnection.h" +#include "libpq++/pgdatabase.h" +#include "libpq++/pgtransdb.h" +#include "libpq++/pgcursordb.h" +#include "libpq++/pglobject.h" + +#endif // LIBPQXX_H + diff --git a/src/interfaces/libpq++/pgconnection.cc b/src/interfaces/libpq++/pgconnection.cc index 777a12e8e7..96ef215700 100644 --- a/src/interfaces/libpq++/pgconnection.cc +++ b/src/interfaces/libpq++/pgconnection.cc @@ -1,94 +1,169 @@ /*------------------------------------------------------------------------- * * FILE - * pgconnection.cc + * pgconnection.cpp * * DESCRIPTION - * implementation of the PGconnection class. - * PGconnection encapsulates a frontend to backend connection + * implementation of the PgConnection class. + * PgConnection encapsulates a frontend to backend connection * * Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/interfaces/libpq++/Attic/pgconnection.cc,v 1.1.1.1 1996/07/09 06:22:18 scrappy Exp $ + * $Header: /cvsroot/pgsql/src/interfaces/libpq++/Attic/pgconnection.cc,v 1.2 1997/02/13 10:00:27 scrappy Exp $ * *------------------------------------------------------------------------- */ -#include "libpq++.H" +#include +#include +#include "pgconnection.h" + +extern "C" { +#include "fe-auth.h" +} -// default constructor -// checks environment variable for database name -PGconnection::PGconnection() -{ - char* name; - PGenv* newenv; - conn = NULL; - result = NULL; - errorMessage[0] = '\0'; +// **************************************************************** +// +// PgConnection Implementation +// +// **************************************************************** +// default constructor -- initialize everything +PgConnection::PgConnection() + : pgConn(NULL), pgResult(NULL), pgCloseConnection(0) +{} - newenv = new PGenv(); // use reasonable defaults for the environment - if (!(name = getenv(ENV_DEFAULT_DBASE))) - return; - connect(newenv, name); +// copy constructor -- copy the pointers; no deep copy required +PgConnection::PgConnection(const PgConnection& conn) + : pgEnv(conn.pgEnv), pgConn(conn.pgConn), pgResult(conn.pgResult), + pgCloseConnection(conn.pgCloseConnection) +{} + +// constructor -- checks environment variable for database name +PgConnection::PgConnection(const char* dbName) + : pgConn(NULL), pgResult(NULL), pgCloseConnection(1) +{ + // Get a default database name to connect to + char* defDB = (char*)dbName; + if ( !dbName ) + if ( !(defDB = getenv(ENV_DEFAULT_DBASE)) ) + return; + + // Connect to the database + Connect( defDB ); } // constructor -- for given environment and database name -PGconnection::PGconnection(PGenv* env, char* dbName) +PgConnection::PgConnection(const PgEnv& env, const char* dbName) + : pgEnv(env), pgConn(NULL), pgResult(NULL), pgCloseConnection(1) { - conn = NULL; - result = NULL; - errorMessage[0] = '\0'; - connect(env, dbName); + Connect( dbName ); } // destructor - closes down the connection and cleanup -PGconnection::~PGconnection() +PgConnection::~PgConnection() { - if (result) PQclear(result); - if (conn) PQfinish(conn); + // Terminate the debugging output if it was turned on + #if defined(DEBUG) + PQuntrace(pgConn); + #endif + + // Close the conneciton only if needed + // This feature will most probably be used by the derived classes that + // need not close the connection after they are destructed. + if ( pgCloseConnection ) { + if (pgResult) PQclear(pgResult); + if (pgConn) PQfinish(pgConn); + } } -// PGconnection::connect +// PgConnection::connect // establish a connection to a backend -ConnStatusType -PGconnection::connect(PGenv* newenv, char* dbName) +ConnStatusType PgConnection::Connect(const char* dbName) { -#if 0 - FILE *debug; - debug = fopen("/tmp/trace.out","w"); - PQtrace(conn, debug); -#endif - - env = newenv; - fe_setauthsvc(env->pgauth, errorMessage); - conn = PQsetdb(env->pghost, env->pgport, env->pgoption, env->pgtty, dbName); - if(strlen(errorMessage)) - return CONNECTION_BAD; + // Turn the trace on + #if defined(DEBUG) + FILE *debug = fopen("/tmp/trace.out","w"); + PQtrace(pgConn, debug); + #endif + + // Set Host Authentication service + char errorMessage[ERROR_MSG_LENGTH]; + memset(errorMessage, 0, sizeof(errorMessage)); + fe_setauthsvc(pgEnv.Auth(), errorMessage); + + // Connect to the database + pgConn = PQsetdb(pgEnv.Host(), pgEnv.Port(), pgEnv.Option(), pgEnv.TTY(), dbName); + + // Return the connection status + if (errorMessage) { + SetErrorMessage( errorMessage ); + return CONNECTION_BAD; + } else - return status(); + return Status(); } -// PGconnection::status -- return connection or result status -ConnStatusType -PGconnection::status() +// PgConnection::status -- return connection or result status +ConnStatusType PgConnection::Status() { - return PQstatus(conn); + return PQstatus(pgConn); } -// PGconnection::exec -- send a query to the backend -ExecStatusType -PGconnection::exec(char* query) +// PgConnection::exec -- send a query to the backend +ExecStatusType PgConnection::Exec(const char* query) { - if (result) - PQclear(result); + // Clear the Result Stucture if needed + if (pgResult) + PQclear(pgResult); - result = PQexec(conn, query); - if (result) - return PQresultStatus(result); + // Execute the given query + pgResult = PQexec(pgConn, query); + + // Return the status + if (pgResult) + return PQresultStatus(pgResult); else { - strcpy(errorMessage, PQerrorMessage(conn)); + SetErrorMessage( PQerrorMessage(pgConn) ); return PGRES_FATAL_ERROR; } } + +// Return true if the Postgres command was executed OK +int PgConnection::ExecCommandOk(const char* query) +{ + return Exec(query) == PGRES_COMMAND_OK; +} // End ExecCommandOk() + +int PgConnection::ExecTuplesOk(const char* query) +{ + return Exec(query) == PGRES_TUPLES_OK; +} // End ExecTuplesOk() + + +// PgConnection::notifies() -- returns a notification from a list of unhandled notifications +PGnotify* PgConnection::Notifies() +{ + Exec(" "); + return PQnotifies(pgConn); +} + +// PgConnection::SetErrorMessage +// sets error message to the given string +void PgConnection::SetErrorMessage(const string& msg, int append) +{ + if ( append ) + pgErrorMessage += msg; + else + pgErrorMessage = msg; +} + +// From Integer To String Conversion Function +string PgConnection::IntToString(int n) +{ + char buffer [32]; + memset(buffer, 0, sizeof(buffer)); + sprintf(buffer, "%d", n); + return buffer; +} diff --git a/src/interfaces/libpq++/pgconnection.h b/src/interfaces/libpq++/pgconnection.h new file mode 100644 index 0000000000..125c9427a5 --- /dev/null +++ b/src/interfaces/libpq++/pgconnection.h @@ -0,0 +1,75 @@ +/*------------------------------------------------------------------------- + * + * pgconnection.h + * + * + * DESCRIPTION + * Postgres Connection Class: + * Manage Postgres backend connection + * + * NOTES + * Currently under construction. + * + * Copyright (c) 1994, Regents of the University of California + * + *------------------------------------------------------------------------- + */ + +#ifndef PGCONN_H +#define PGCONN_H + +#include +#include "pgenv.h" + +extern "C" { +#include "libpq-fe.h" +} + + +// **************************************************************** +// +// PgConnection - a connection made to a postgres backend +// +// **************************************************************** +// This class contains all the information about the connection +// to the backend process. All the database classes should be +// derived from this class to obtain the connection interface. +class PgConnection { +protected: + PgEnv pgEnv; // Current connection environment + PGconn* pgConn; // Connection Structures + PGresult* pgResult; // Query Result + string pgErrorMessage; // Error messages container + int pgCloseConnection; // Flag indicating whether the connection should be closed or not + +public: + PgConnection(const char* dbName); // use reasonable defaults + PgConnection(const PgEnv& env, const char* dbName); // connect to the database with + // given environment and database name + virtual ~PgConnection(); // close connection and clean up + + // Connection status and error messages + ConnStatusType Status(); + int ConnectionBad() { return Status() == CONNECTION_BAD; } + const char* ErrorMessage() const { return pgErrorMessage.c_str(); } + + // returns the database name of the connection + const char* DBName() const { return PQdb(pgConn); } + + // Query Execution interface + ExecStatusType Exec(const char* query); // send a query to the backend + int ExecCommandOk(const char* query); // send a command and check if it's OK + int ExecTuplesOk(const char* query); // send a command and check if tuples are returned + PGnotify* Notifies(); + +protected: + ConnStatusType Connect(const char* dbName); + void SetErrorMessage(const string&, int append = 0); + string IntToString(int); + +protected: + PgConnection(); + PgConnection(const PgConnection&); +}; + +#endif // PGCONN_H diff --git a/src/interfaces/libpq++/pgcursordb.cc b/src/interfaces/libpq++/pgcursordb.cc new file mode 100644 index 0000000000..0589996940 --- /dev/null +++ b/src/interfaces/libpq++/pgcursordb.cc @@ -0,0 +1,90 @@ +/*------------------------------------------------------------------------- + * + * FILE + * pgcursordb.cpp + * + * DESCRIPTION + * implementation of the PgCursor class. + * PgCursor encapsulates a cursor interface to the backend + * + * Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * $Header: /cvsroot/pgsql/src/interfaces/libpq++/Attic/pgcursordb.cc,v 1.1 1997/02/13 10:00:30 scrappy Exp $ + * + *------------------------------------------------------------------------- + */ + + #include "pgcursordb.h" + + +// **************************************************************** +// +// PgCursor Implementation +// +// **************************************************************** +// Make a connection to the specified database with default environment +PgCursor::PgCursor(const char* dbName, const char* cursor) + : PgTransaction(dbName), pgCursor(cursor) +{} + +// Make a connection to the specified database with the given environment +PgCursor::PgCursor(const PgEnv& env, const char* dbName, const char* cursor) + : PgTransaction(env, dbName), pgCursor(cursor) +{} + +// Do not make a connection to the backend -- just query +// Connection should not be closed after the object destructs since some +// other object is using the connection +PgCursor::PgCursor(const PgConnection& conn, const char* cursor) + : PgTransaction(conn), pgCursor(cursor) +{} + +// Destructor: End the transaction block +PgCursor::~PgCursor() +{ + Close(); +} + + +// **************************************************************** +// +// PgCursor: Cursor Interface Implementation +// +// **************************************************************** +// Declare a cursor: name has already been supplied in the constructor +int PgCursor::Declare(const string& query, int binary) +{ + string cmd = "DECLARE " + pgCursor; + if ( binary ) + cmd += " BINARY"; + cmd += " CURSOR FOR " + query; + return ExecCommandOk( cmd.c_str() ); +} // End Declare() + +// Fetch ALL tuples in given direction +int PgCursor::Fetch(const char* dir) +{ + return Fetch("ALL", dir); +} // End Fetch() + +// Fetch specified amount of tuples in given direction +int PgCursor::Fetch(unsigned num, const char* dir) +{ + return Fetch( IntToString(num), dir ); +} // End Fetch() + +// Create and execute the actual fetch command with the given arguments +int PgCursor::Fetch(const string& num, const string& dir) +{ + string cmd = "FETCH " + dir + " " + num + " IN " + pgCursor; + return ExecTuplesOk( cmd.c_str() ); +} // End Fetch() + +// Close the cursor: no more queries using the cursor should be allowed +// Actually, the backend should take care of it. +int PgCursor::Close() +{ + string cmd = "CLOSE " + pgCursor; + return ExecCommandOk( cmd.c_str() ); +} // End CloseCursor() diff --git a/src/interfaces/libpq++/pgcursordb.h b/src/interfaces/libpq++/pgcursordb.h new file mode 100644 index 0000000000..de1adafb2f --- /dev/null +++ b/src/interfaces/libpq++/pgcursordb.h @@ -0,0 +1,61 @@ +/*------------------------------------------------------------------------- + * + * pgcursordb.h + * + * + * DESCRIPTION + * Postgres Cursor Database Class: + * Query Postgres backend using a cursor + * + * NOTES + * Currently under construction. + * + * Copyright (c) 1994, Regents of the University of California + * + *------------------------------------------------------------------------- + */ + +#ifndef PGCURSOR_H +#define PGCURSOR_H + +#include "pgtransdb.h" + + +// **************************************************************** +// +// PgCursor - a class for querying databases using a cursor +// +// **************************************************************** +// This is the database access class that declares a cursor and +// manipulates data through it. The interface will introduce some +// ease of use through the methods that will allow cursor specific +// operations, like fetch, forward, etc. +class PgCursor : public PgTransaction { +public: + PgCursor(const char* dbName, const char* cursor); // use reasonable defaults + // connect to the database with given environment and database name + PgCursor(const PgEnv& env, const char* dbName, const char* cursor); + PgCursor(const PgConnection&, const char* cursor); + virtual ~PgCursor(); // close connection and clean up + + // Commands associated with cursor interface + int Declare(const string& query, int binary = 0); // Declare a cursor with given name + int Fetch(const char* dir = "FORWARD"); // Fetch ALL tuples in given direction + int Fetch(unsigned num, const char* dir = "FORWARD"); // Fetch specified amount of tuples + int Close(); // Close the cursor + + // Accessors to the cursor name + const char* Cursor() const { return pgCursor.c_str(); } + void Cursor(const string& cursor) { pgCursor = cursor; } + +protected: + int Fetch(const string& num, const string& dir); + +protected: + string pgCursor; + +protected: + PgCursor() : PgTransaction() {} // Do not connect +}; // End PgCursor Class Declaration + +#endif // PGCURSOR_H diff --git a/src/interfaces/libpq++/pgdatabase.h b/src/interfaces/libpq++/pgdatabase.h new file mode 100644 index 0000000000..c3c904234c --- /dev/null +++ b/src/interfaces/libpq++/pgdatabase.h @@ -0,0 +1,85 @@ +/*------------------------------------------------------------------------- + * + * pgdatabase.h + * + * + * DESCRIPTION + * Postgres Database Class: + * Query Postgres backend to obtain query results + * + * NOTES + * Currently under construction. + * + * Copyright (c) 1994, Regents of the University of California + * + *------------------------------------------------------------------------- + */ + +#ifndef PGDATABASE_H +#define PGDATABASE_H + +#include "pgconnection.h" + + +// **************************************************************** +// +// PgDatabase - a class for accessing databases +// +// **************************************************************** +// This is the basic database access class. Its interface should +// be used only after a query has been sent to the backend and +// results are being received. +class PgDatabase : public PgConnection { +public: + PgDatabase(const char* dbName) : PgConnection(dbName) {} // use reasonable defaults + // connect to the database with given environment and database name + PgDatabase(const PgEnv& env, const char* dbName) : PgConnection(env, dbName) {} + PgDatabase(const PgConnection& conn) : PgConnection(conn) {pgCloseConnection = 0;} + ~PgDatabase() {} // close connection and clean up + + // query result access + int Tuples() + { return PQntuples(pgResult); } + int Fields() + { return PQnfields(pgResult); } + const char* FieldName(int field_num) + { return PQfname(pgResult, field_num); } + int FieldNum(const char* field_name) + { return PQfnumber(pgResult, field_name); } + Oid FieldType(int field_num) + { return PQftype(pgResult, field_num); } + Oid FieldType(const char* field_name) + { return PQftype(pgResult, FieldNum(field_name)); } + short FieldSize(int field_num) + { return PQfsize(pgResult, field_num); } + short FieldSize(const char* field_name) + { return PQfsize(pgResult, FieldNum(field_name)); } + const char* GetValue(int tup_num, int field_num) + { return PQgetvalue(pgResult, tup_num, field_num); } + const char* GetValue(int tup_num, const char* field_name) + { return PQgetvalue(pgResult, tup_num, FieldNum(field_name)); } + int GetLength(int tup_num, int field_num) + { return PQgetlength(pgResult, tup_num, field_num); } + int GetLength(int tup_num, const char* field_name) + { return PQgetlength(pgResult, tup_num, FieldNum(field_name)); } + void DisplayTuples(FILE *out = 0, int fillAlign = 1, const char* fieldSep = "|", + int printHeader = 1, int quiet = 0) + { PQdisplayTuples(pgResult, (out ? out : stdout), fillAlign, fieldSep, printHeader, quiet); } + void PrintTuples(FILE *out = 0, int printAttName = 1, int terseOutput = 0, int width = 0) + { PQprintTuples(pgResult, (out ? out : stdout), printAttName, terseOutput, width); } + + // copy command related access + int GetLine(char* string, int length) + { return PQgetline(pgConn, string, length); } + void PutLine(const char* string) + { PQputline(pgConn, string); } + const char* OidStatus() + { return PQoidStatus(pgResult); } + int EndCopy() + { return PQendcopy(pgConn); } + +protected: + PgDatabase() : PgConnection() {} // Do not connect +}; + +#endif // PGDATABASE_H diff --git a/src/interfaces/libpq++/pgenv.cc b/src/interfaces/libpq++/pgenv.cc index 7d696cf043..451a4f3fde 100644 --- a/src/interfaces/libpq++/pgenv.cc +++ b/src/interfaces/libpq++/pgenv.cc @@ -1,10 +1,10 @@ /*------------------------------------------------------------------------- * * FILE - * PGenv.cc + * PgEnv.cc * * DESCRIPTION - * PGenv is the environment for setting up a connection to a + * PgEnv is the environment for setting up a connection to a * postgres backend, captures the host, port, tty, options and * authentication type. * @@ -14,94 +14,55 @@ * Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/interfaces/libpq++/Attic/pgenv.cc,v 1.2 1996/11/18 01:43:55 bryanh Exp $ + * $Header: /cvsroot/pgsql/src/interfaces/libpq++/Attic/pgenv.cc,v 1.3 1997/02/13 10:00:33 scrappy Exp $ * *------------------------------------------------------------------------- */ #include -#include "libpq++.H" +#include "pgenv.h" -#define DefaultAuth DEFAULT_CLIENT_AUTHSVC -#define DefaultPort "5432" -// default constructor for PGenv +#define DefaultAuth DEFAULT_CLIENT_AUTHSVC +#define DefaultPort POSTPORT + + +// **************************************************************** +// +// PgEnv Implementation +// +// **************************************************************** +// Default constructor for PgEnv // checks the environment variables -PGenv::PGenv() +PgEnv::PgEnv() { - pgauth = NULL; - pghost = NULL; - pgport = NULL; - pgoption = NULL; - pgtty = NULL; - - setValues(getenv(ENV_DEFAULT_AUTH), getenv(ENV_DEFAULT_HOST), + SetValues(getenv(ENV_DEFAULT_AUTH), getenv(ENV_DEFAULT_HOST), getenv(ENV_DEFAULT_PORT), getenv(ENV_DEFAULT_OPTION), - getenv(ENV_DEFAULT_TTY)); + getenv(ENV_DEFAULT_TTY)); } // constructor for given environment -PGenv::PGenv(char* auth, char* host, char* port, char* option, char* tty) +PgEnv::PgEnv(const string& auth, const string& host, const string& port, + const string& option, const string& tty) { - pgauth = NULL; - pghost = NULL; - pgport = NULL; - pgoption = NULL; - pgtty = NULL; - - setValues(auth, host, port, option, tty); + SetValues(auth, host, port, option, tty); } // allocate memory and set internal structures to match // required environment -void -PGenv::setValues(char* auth, char* host, char* port, char* option, char* tty) +void PgEnv::SetValues(const string& auth, const string& host, const string& port, + const string& option, const string& tty) { - char* temp; - - temp = (auth) ? auth : DefaultAuth; - - if (pgauth) - free(pgauth); - pgauth = strdup(temp); - - temp = (host) ? host : DefaultHost; - - if (pghost) - free(pghost); - pghost = strdup(temp); - - temp = (port) ? port : DefaultPort; - - if (pgport) - free(pgport); - pgport = strdup(temp); - - temp = (option) ? option : DefaultOption; - - if (pgoption) - free(pgoption); - pgoption = strdup(temp); - - temp = (tty) ? tty : DefaultTty; - - if (pgtty) - free(pgtty); - pgtty = strdup(temp); + Auth( auth ); + Host( host ); + Port( port ); + Option( option ); + TTY( tty ); } -// default destrutor -// frees allocated memory for internal structures -PGenv::~PGenv() +// read a string from the environment and convert it to string +string PgEnv::getenv(const char* name) { - if (pgauth) - free(pgauth); - if (pghost) - free(pghost); - if (pgport) - free(pgport); - if (pgoption) - free(pgoption); - if (pgtty) - free(pgtty); + char* env = ::getenv(name); + return (env ? env : ""); } diff --git a/src/interfaces/libpq++/pgenv.h b/src/interfaces/libpq++/pgenv.h new file mode 100644 index 0000000000..768c5d86b9 --- /dev/null +++ b/src/interfaces/libpq++/pgenv.h @@ -0,0 +1,79 @@ +/*------------------------------------------------------------------------- + * + * pgenv.h + * + * + * DESCRIPTION + * Postgres Environment Class: manages and stores all the required + * connection variables. + * + * NOTES + * Currently under construction. + * + * Copyright (c) 1994, Regents of the University of California + * + *------------------------------------------------------------------------- + */ + +#ifndef PGENV_H +#define PGENV_H + +#include + + +// +// these are the environment variables used for getting defaults +// + +#define ENV_DEFAULT_AUTH "PGAUTH" +#define ENV_DEFAULT_DBASE "PGDATABASE" +#define ENV_DEFAULT_HOST "PGHOST" +#define ENV_DEFAULT_OPTION "PGOPTION" +#define ENV_DEFAULT_PORT "PGPORT" +#define ENV_DEFAULT_TTY "PGTTY" + + +// **************************************************************** +// +// PgEnv - the environment for setting up a connection to postgres +// +// **************************************************************** +class PgEnv { +private: + string pgAuth; + string pgHost; + string pgPort; + string pgOption; + string pgTty; + +public: + PgEnv(); // default ctor will use reasonable defaults + // will use environment variables PGHOST, PGPORT, + // PGOPTION, PGTTY + PgEnv(const string& auth, const string& host, const string& port, + const string& option, const string& tty); + + // Access methods to all the environment variables + const char* Auth() { return pgAuth.c_str(); } + void Auth(const string& auth) { pgAuth = auth; } + + const char* Host() { return pgHost.c_str(); } + void Host(const string& host) { pgHost = host; } + + const char* Port() { return pgPort.c_str(); } + void Port(const string& port) { pgPort = port; } + + const char* Option() { return pgOption.c_str(); } + void Option(const string& option) { pgOption = option; } + + const char* TTY() { return pgTty.c_str(); } + void TTY(const string& tty) { pgTty = tty; } + + void SetValues(const string& auth, const string& host, const string& port, + const string& option, const string& tty); + +protected: + string getenv(const char*); +}; + +#endif // PGENV_H diff --git a/src/interfaces/libpq++/pglobject.cc b/src/interfaces/libpq++/pglobject.cc index 4de4a1f0d9..917a368f50 100644 --- a/src/interfaces/libpq++/pglobject.cc +++ b/src/interfaces/libpq++/pglobject.cc @@ -1,154 +1,129 @@ - /*------------------------------------------------------------------------- * * FILE * pglobject.cc * * DESCRIPTION - * implementation of the PGlobj class. - * PGlobj encapsulates a frontend to backend connection + * implementation of the PgLargeObject class. + * PgLargeObject encapsulates a frontend to backend connection * * Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/interfaces/libpq++/Attic/pglobject.cc,v 1.2 1996/11/12 11:42:31 bryanh Exp $ + * $Header: /cvsroot/pgsql/src/interfaces/libpq++/Attic/pglobject.cc,v 1.3 1997/02/13 10:00:34 scrappy Exp $ * *------------------------------------------------------------------------- */ -#include "libpq++.H" - + extern "C" { -#include -#include #include "libpq/libpq-fs.h" } +#include "pglobject.h" + + + +// **************************************************************** +// +// PgLargeObject Implementation +// +// **************************************************************** // default constructor // creates a large object in the default database -PGlobj::PGlobj() : PGconnection::PGconnection() { - object = lo_creat(conn, INV_READ|INV_WRITE); - if (object == 0) { - sprintf(errorMessage, "PGlobj: can't create large object"); - } - fd = lo_open(conn, object, INV_READ|INV_WRITE); - if (fd < 0) { - sprintf(errorMessage, "PGlobj: can't open large object %d", object); - } else - sprintf(errorMessage, "PGlobj: created and opened large object %d", - object); - +PgLargeObject::PgLargeObject(const char* dbName) + : PgConnection(dbName) +{ + Init(); + Create(); + Open(); } // constructor // open an existing large object in the default database -PGlobj::PGlobj(Oid lobjId) : PGconnection::PGconnection() { - object = lobjId; - fd = lo_open(conn, object, INV_READ|INV_WRITE); - if (fd < 0) { - sprintf(errorMessage, "PGlobj: can't open large object %d", object); - } else - sprintf(errorMessage, "PGlobj: opened large object %d", - object); +PgLargeObject::PgLargeObject(Oid lobjId, const char* dbName) + : PgConnection(dbName) +{ + Init(lobjId); + if ( !pgObject ) + Create(); + Open(); } // constructor // create a large object in the given database -PGlobj::PGlobj(PGenv* env, char* dbName) : PGconnection::PGconnection(env,dbName) { - object = lo_creat(conn, INV_READ|INV_WRITE); - if (object == 0) { - sprintf(errorMessage, "PGlobj: can't create large object"); - } - fd = lo_open(conn, object, INV_READ|INV_WRITE); - if (fd < 0) { - sprintf(errorMessage, "PGlobj: can't open large object %d", object); - } else - sprintf(errorMessage, "PGlobj: created and opened large object %d", - object); +PgLargeObject::PgLargeObject(const PgEnv& env, const char* dbName) + : PgConnection(env, dbName) +{ + Init(); + Create(); + Open(); } // constructor // open an existing large object in the given database -PGlobj::PGlobj(PGenv* env, char* dbName, Oid lobjId) : PGconnection::PGconnection(env,dbName) { - object = lobjId; - fd = lo_open(conn, object, INV_READ|INV_WRITE); - if (fd < 0) { - sprintf(errorMessage, "PGlobj: can't open large object %d", object); - } else - sprintf(errorMessage, "PGlobj: created and opened large object %d", - object); +PgLargeObject::PgLargeObject(const PgEnv& env, const char* dbName, Oid lobjId) + : PgConnection(env, dbName) +{ + Init(lobjId); + if ( !pgObject ) + Create(); + Open(); } -// PGlobj::unlink -// destruct large object and delete from it from the database -int -PGlobj::unlink() { - int temp = lo_unlink(conn, object); - if (temp) { - return temp; - } else { - delete this; - return temp; - } +// destructor -- closes large object +PgLargeObject::~PgLargeObject() +{ + Close(); } -// PGlobj::import -- import a given file into the large object -int -PGlobj::import(char* filename) { - char buf[BUFSIZE]; - int nbytes, tmp; - int in_fd; - - // open the file to be read in - in_fd = open(filename, O_RDONLY, 0666); - if (in_fd < 0) { /* error */ - sprintf(errorMessage, "PGlobj::import: can't open unix file\"%s\"", filename); - return -1; - } - - // read in from the Unix file and write to the inversion file - while ((nbytes = ::read(in_fd, buf, BUFSIZE)) > 0) { - tmp = lo_write(conn, fd, buf, nbytes); - if (tmp < nbytes) { - sprintf(errorMessage, "PGlobj::import: error while reading \"%s\"", - filename); - return -1; - } - } - - (void) close(in_fd); - return 0; +// PgLargeObject::Init +// Initialize the variables +void PgLargeObject::Init(Oid lobjId) +{ + pgFd = -1; + pgObject = lobjId; } -// PGlobj::export -- export large object to given file -int -PGlobj::export(char* filename) { - int out_fd; - char buf[BUFSIZE]; - int nbytes, tmp; - - // open the file to be written to - out_fd = open(filename, O_CREAT|O_WRONLY, 0666); - if (out_fd < 0) { /* error */ - sprintf(errorMessage, "PGlobj::export: can't open unix file\"%s\"", - filename); - return -1; - } +// PgLargeObject::create +// create large object and check for errors +void PgLargeObject::Create() +{ + // Create the object + pgObject = lo_creat(pgConn, INV_READ|INV_WRITE); + + // Check for possible errors + if (!pgObject) + SetErrorMessage( "PgLargeObject: can't create large object" ); +} - // read in from the Unix file and write to the inversion file - while ((nbytes = lo_read(conn, fd, buf, BUFSIZE)) > 0) { - tmp = ::write(out_fd, buf, nbytes); - if (tmp < nbytes) { - sprintf(errorMessage,"PGlobj::export: error while writing \"%s\"", - filename); - return -1; - } - } - (void) close(out_fd); - return 0; +// PgLargeObject::open +// open large object and check for errors +void PgLargeObject::Open() +{ + // Open the object + pgFd = lo_open(pgConn, pgObject, INV_READ|INV_WRITE); + + // Check for possible errors + string objStr( IntToString(pgObject) ); + if (pgFd < 0) + SetErrorMessage( "PgLargeObject: can't open large object " + objStr ); + else + SetErrorMessage( "PgLargeObject: created and opened large object " + objStr ); } -// default destructor -- closes large object -PGlobj::~PGlobj() { - if (fd >= 0) - lo_close(conn, fd); +// PgLargeObject::unlink +// destruct large object and delete from it from the database +int PgLargeObject::Unlink() +{ + // Unlink the object + int temp = lo_unlink(pgConn, pgObject); + + // Initialize the large object upon success + if (!temp) { + Close(); + Init(); + } + + // Return the status + return temp; } diff --git a/src/interfaces/libpq++/pglobject.h b/src/interfaces/libpq++/pglobject.h new file mode 100644 index 0000000000..9fcd3449a2 --- /dev/null +++ b/src/interfaces/libpq++/pglobject.h @@ -0,0 +1,64 @@ +/*------------------------------------------------------------------------- + * + * FILE + * pglobject.h + * + * DESCRIPTION + * declaration of the PGlobj class. + * PGlobj encapsulates a large object interface to Postgres backend + * + * Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * $Header: /cvsroot/pgsql/src/interfaces/libpq++/Attic/pglobject.h,v 1.1 1997/02/13 10:00:35 scrappy Exp $ + * + *------------------------------------------------------------------------- + */ + +#ifndef PGLOBJ_H +#define PGLOBJ_H + +#include "pgconnection.h" + +// buffer size +#define BUFSIZE 1024 + + +// **************************************************************** +// +// PgLargeObject - a class for accessing Large Object in a database +// +// **************************************************************** +class PgLargeObject : public PgConnection { +private: + int pgFd; + Oid pgObject; + +public: + PgLargeObject(const char* dbName = 0); // use reasonable defaults and create large object + PgLargeObject(Oid lobjId, const char* dbName = 0); // use reasonable defaults and open large object + PgLargeObject(const PgEnv& env, const char* dbName); // create large object + PgLargeObject(const PgEnv& env, const char* dbName, Oid lobjId); // open large object + ~PgLargeObject(); // close connection and clean up + + void Create(); + void Open(); + void Close() + { if (pgFd >= 0) lo_close(pgConn, pgFd); } + int Read(char* buf, int len) + { return lo_read(pgConn, pgFd, buf, len); } + int Write(const char* buf, int len) + { return lo_write(pgConn, pgFd, (char*)buf, len); } + int LSeek(int offset, int whence) + { return lo_lseek(pgConn, pgFd, offset, whence); } + int Tell() + { return lo_tell(pgConn, pgFd); } + int Unlink(); + Oid Import(const char* filename) { return pgObject = lo_import(pgConn, (char*)filename); } + int Export(const char* filename) { return lo_export(pgConn, pgObject, (char*)filename); } + +private: + void Init(Oid lobjId = 0); +}; + +#endif // PGLOBJ_H diff --git a/src/interfaces/libpq++/pgtransdb.cc b/src/interfaces/libpq++/pgtransdb.cc new file mode 100644 index 0000000000..cef16a2004 --- /dev/null +++ b/src/interfaces/libpq++/pgtransdb.cc @@ -0,0 +1,65 @@ +/*------------------------------------------------------------------------- + * + * FILE + * pgtransdb.cpp + * + * DESCRIPTION + * implementation of the PgTransaction class. + * PgConnection encapsulates a transaction querying to backend + * + * Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * $Header: /cvsroot/pgsql/src/interfaces/libpq++/Attic/pgtransdb.cc,v 1.1 1997/02/13 10:00:36 scrappy Exp $ + * + *------------------------------------------------------------------------- + */ + + #include "pgtransdb.h" + + +// **************************************************************** +// +// PgTransaction Implementation +// +// **************************************************************** +// Make a connection to the specified database with default environment +PgTransaction::PgTransaction(const char* dbName) + : PgDatabase(dbName) +{ + BeginTransaction(); +} + +// Make a connection to the specified database with the given environment +PgTransaction::PgTransaction(const PgEnv& env, const char* dbName) + : PgDatabase(env, dbName) +{ + BeginTransaction(); +} + +// Do not make a connection to the backend -- just query +// Connection should not be closed after the object destructs since some +// other object is using the connection +PgTransaction::PgTransaction(const PgConnection& conn) + : PgDatabase(conn) +{ + BeginTransaction(); +} + +// Destructor: End the transaction block +PgTransaction::~PgTransaction() +{ + EndTransaction(); +} + +// Begin the transaction block +ExecStatusType PgTransaction::BeginTransaction() +{ + return Exec("BEGIN"); +} // End BeginTransaction() + +// Begin the transaction block +ExecStatusType PgTransaction::EndTransaction() +{ + return Exec("END"); +} // End EndTransaction() diff --git a/src/interfaces/libpq++/pgtransdb.h b/src/interfaces/libpq++/pgtransdb.h new file mode 100644 index 0000000000..4bce4b1e7b --- /dev/null +++ b/src/interfaces/libpq++/pgtransdb.h @@ -0,0 +1,48 @@ +/*------------------------------------------------------------------------- + * + * pgtransdb.h + * + * + * DESCRIPTION + * Postgres Transaction Database Class: + * Query Postgres backend using a transaction block + * + * NOTES + * Currently under construction. + * + * Copyright (c) 1994, Regents of the University of California + * + *------------------------------------------------------------------------- + */ + +#ifndef PGTRANSDB_H +#define PGTRANSDB_H + +#include "pgdatabase.h" + + +// **************************************************************** +// +// PgTransaction - a class for running transactions against databases +// +// **************************************************************** +// This is the database access class that keeps an open +// transaction block during its lifetime. The block is ENDed when +// the object is destroyed. +class PgTransaction : public PgDatabase { +public: + PgTransaction(const char* dbName); // use reasonable defaults + // connect to the database with given environment and database name + PgTransaction(const PgEnv& env, const char* dbName); + PgTransaction(const PgConnection&); + virtual ~PgTransaction(); // close connection and clean up + +protected: + ExecStatusType BeginTransaction(); + ExecStatusType EndTransaction(); + +protected: + PgTransaction() : PgDatabase() {} // Do not connect +}; // End PgTransaction Class Declaration + +#endif // PGTRANSDB_H