diff options
| author | Marc G. Fournier <scrappy@hub.org> | 1996-07-09 06:22:35 +0000 |
|---|---|---|
| committer | Marc G. Fournier <scrappy@hub.org> | 1996-07-09 06:22:35 +0000 |
| commit | d31084e9d1118b25fd16580d9d8c2924b5740dff (patch) | |
| tree | 3179e66307d54df9c7b966543550e601eb55e668 /src/interfaces/libpq++ | |
| download | postgresql-d31084e9d1118b25fd16580d9d8c2924b5740dff.tar.gz | |
Postgres95 1.01 Distribution - Virgin SourcesPG95-1_01
Diffstat (limited to 'src/interfaces/libpq++')
| -rw-r--r-- | src/interfaces/libpq++/Makefile | 54 | ||||
| -rw-r--r-- | src/interfaces/libpq++/README | 22 | ||||
| -rw-r--r-- | src/interfaces/libpq++/examples/Makefile | 70 | ||||
| -rw-r--r-- | src/interfaces/libpq++/examples/testlibpq0.cc | 49 | ||||
| -rw-r--r-- | src/interfaces/libpq++/examples/testlibpq1.cc | 84 | ||||
| -rw-r--r-- | src/interfaces/libpq++/examples/testlibpq2.cc | 71 | ||||
| -rw-r--r-- | src/interfaces/libpq++/examples/testlibpq2.sql | 5 | ||||
| -rw-r--r-- | src/interfaces/libpq++/examples/testlibpq3.cc | 131 | ||||
| -rw-r--r-- | src/interfaces/libpq++/examples/testlibpq3.sql | 6 | ||||
| -rw-r--r-- | src/interfaces/libpq++/examples/testlibpq4.cc | 69 | ||||
| -rw-r--r-- | src/interfaces/libpq++/examples/testlo.cc | 63 | ||||
| -rw-r--r-- | src/interfaces/libpq++/libpq++.H | 173 | ||||
| -rw-r--r-- | src/interfaces/libpq++/man/libpq++.3 | 434 | ||||
| -rw-r--r-- | src/interfaces/libpq++/pgconnection.cc | 94 | ||||
| -rw-r--r-- | src/interfaces/libpq++/pgenv.cc | 109 | ||||
| -rw-r--r-- | src/interfaces/libpq++/pglobject.cc | 152 |
16 files changed, 1586 insertions, 0 deletions
diff --git a/src/interfaces/libpq++/Makefile b/src/interfaces/libpq++/Makefile new file mode 100644 index 0000000000..e1d58847ee --- /dev/null +++ b/src/interfaces/libpq++/Makefile @@ -0,0 +1,54 @@ +#------------------------------------------------------------------------- +# +# Makefile +# Makefile for libpq++ library +# +# Copyright (c) 1994, Regents of the University of California +# +# +# IDENTIFICATION +# $Header: /cvsroot/pgsql/src/interfaces/libpq++/Attic/Makefile,v 1.1.1.1 1996/07/09 06:22:18 scrappy Exp $ +# +#------------------------------------------------------------------------- + +CPP_LIB= true + +LIB= pq++ + +MKDIR= ../mk +include $(MKDIR)/postgres.mk + +CXXFLAGS = $(CFLAGS) + +CXXFLAGS+= -I$(srcdir)/backend/include \ + -I$(srcdir)/backend \ + -I$(srcdir)/libpq \ + -I$(CURDIR) \ + +ifdef KRBVERS +CXXFLAGS+= $(KRBFLAGS) +endif + + +LIBSRCS = pgenv.cc pgconnection.cc pglobject.cc + +.PHONY: beforeinstall-headers install-headers + +ifndef NO_BEFOREINSTL +beforeinstall-headers: + @-if [ ! -d $(HEADERDIR) ]; then mkdir $(HEADERDIR); fi +else +beforeinstall-headers: .dosomething +endif + +HEADERFILES = libpq++.H + +install-headers: beforeinstall-headers + @for i in ${HEADERFILES}; do \ + echo "Installing $(HEADERDIR)/$$i."; \ + $(INSTALL) -c -m 444 $$i $(HEADERDIR)/$$i; \ + done + +install:: install-headers + +include $(MKDIR)/postgres.lib.mk diff --git a/src/interfaces/libpq++/README b/src/interfaces/libpq++/README new file mode 100644 index 0000000000..cb5d0aeddb --- /dev/null +++ b/src/interfaces/libpq++/README @@ -0,0 +1,22 @@ +This directory contains libpq++, the C++ language interface to POSTGRES95. +libpq++ is implemented on of the libpq library. Users would benefit +from reading the chapter on libpq in the postgres95 users manual +before using libpq++. + +The initial version of this implementation was done by William Wanders +(wwanders@sci.kun.nl) + +This is only a preliminary attempt at providing something useful for +people who would like to use C++ to build frontend applications to +postgres95. The API provided herein is subject to change in later +versions of postgres95. + +For details on how to to use libpq++, see the man page in the man/ +subdirectory and the test programs in the examples/ subdirectory. + +libpq++ has been tested with g++, version 2.7.0 + +- Jolly Chen +jolly@cs.berkeley.edu + +Tue Sep 5 11:09:51 PDT 1995 diff --git a/src/interfaces/libpq++/examples/Makefile b/src/interfaces/libpq++/examples/Makefile new file mode 100644 index 0000000000..5e51d91587 --- /dev/null +++ b/src/interfaces/libpq++/examples/Makefile @@ -0,0 +1,70 @@ +# +# Makefile for example programs +# + +CPP_PROG = true + +MKDIR= ../../mk +include $(MKDIR)/postgres.mk + +CXXFLAGS+= -I$(HEADERDIR) -I$(srcdir)/libpq -I$(srcdir)/backend \ + -I$(srcdir)/backend/include + +LD_ADD+=-L$(LIBDIR) -lpq++ -lpq + +# +# And where libpq goes, so goes the authentication stuff... +# +ifdef KRBVERS +LD_ADD+= $(KRBLIBS) +CXXFLAGS+= $(KRBFLAGS) +endif + +P0_PROG:= testlibpq0 +P0_OBJS:= testlibpq0.o + +$(P0_PROG): $(addprefix $(objdir)/,$(P0_OBJS)) + $(CXX) $(CDEBUG) -o $(objdir)/$(@F) $< $(LD_ADD) + +P1_PROG:= testlibpq1 +P1_OBJS:= testlibpq1.o + +$(P1_PROG): $(addprefix $(objdir)/,$(P1_OBJS)) + $(CXX) $(CDEBUG) -o $(objdir)/$(@F) $< $(LD_ADD) + +P2_PROG:= testlibpq2 +P2_OBJS:= testlibpq2.o + +$(P2_PROG): $(addprefix $(objdir)/,$(P2_OBJS)) + $(CXX) $(CDEBUG) -o $(objdir)/$(@F) $< $(LD_ADD) + +P3_PROG:= testlibpq3 +P3_OBJS:= testlibpq3.o + +$(P3_PROG): $(addprefix $(objdir)/,$(P3_OBJS)) + $(CXX) $(CDEBUG) -o $(objdir)/$(@F) $< $(LD_ADD) + +P4_PROG:= testlibpq4 +P4_OBJS:= testlibpq4.o + +$(P4_PROG): $(addprefix $(objdir)/,$(P4_OBJS)) + $(CXX) $(CDEBUG) -o $(objdir)/$(@F) $< $(LD_ADD) + +P5_PROG:= testlo +P5_OBJS:= testlo.o + +$(P5_PROG): $(addprefix $(objdir)/,$(P5_OBJS)) + $(CXX) $(CDEBUG) -o $(objdir)/$(@F) $< $(LD_ADD) + +OBJS:= $(P0_OBJS) $(P1_OBJS) $(P2_OBJS) $(P3_OBJS) $(P4_OBJS) $(P5_OBJS) +PROGS:= $(P0_PROG) $(P1_PROG) $(P2_PROG) $(P3_PROG) $(P4_PROG) $(P5_PROG) + +CLEANFILES+= $(OBJS) $(PROGS) + +all:: $(PROGS) + +install:: $(PROGS) + @for i in ${PROGS}; do \ + echo "Installing $$i"; \ + $(INSTALL) $(objdir)/$$i $(DESTDIR)$(BINDIR)/$$i;\ + done diff --git a/src/interfaces/libpq++/examples/testlibpq0.cc b/src/interfaces/libpq++/examples/testlibpq0.cc new file mode 100644 index 0000000000..76f3ea8071 --- /dev/null +++ b/src/interfaces/libpq++/examples/testlibpq0.cc @@ -0,0 +1,49 @@ +/*------------------------------------------------------------------------- + * + * testlibpq0.c-- + * small test program for libpq++, + * small interactive loop where queries can be entered interactively + * and sent to the backend + * + * Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * $Header: /cvsroot/pgsql/src/interfaces/libpq++/examples/Attic/testlibpq0.cc,v 1.1.1.1 1996/07/09 06:22:18 scrappy Exp $ + * + *------------------------------------------------------------------------- + */ + +#include <stdio.h> +#include "libpq++.H" + +int +main(int argc, char** argv) +{ + ExecStatusType status; + PGenv env; + PGdatabase* data; + + char buf[10000]; + 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 = %s\nerrorMessage = %s\n", status, + data->errormessage()); + else + done = 1; + } +} diff --git a/src/interfaces/libpq++/examples/testlibpq1.cc b/src/interfaces/libpq++/examples/testlibpq1.cc new file mode 100644 index 0000000000..1d71f79558 --- /dev/null +++ b/src/interfaces/libpq++/examples/testlibpq1.cc @@ -0,0 +1,84 @@ +/* + * testlibpq.cc + * Test the C++ version of LIBPQ, the POSTGRES frontend library. + * + * queries the template1 database for a list of database names + * + */ +#include <stdio.h> +#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; + + /* Select a database */ + dbName = "template1"; + + /* 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); + } + + /* start a transaction block */ + if(data->exec("BEGIN") != PGRES_COMMAND_OK) { + fprintf(stderr,"BEGIN command failed\n"); + delete data; + 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; + 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; + 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"); + + /* 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"); + } + + /* close the portal */ + data->exec("CLOSE myportal"); + + /* end the transaction */ + data->exec("END"); + + /* close the connection to the database and cleanup */ + delete data; +} + + diff --git a/src/interfaces/libpq++/examples/testlibpq2.cc b/src/interfaces/libpq++/examples/testlibpq2.cc new file mode 100644 index 0000000000..8eafea00b7 --- /dev/null +++ b/src/interfaces/libpq++/examples/testlibpq2.cc @@ -0,0 +1,71 @@ +/* + * 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); + + * + * + */ +#include <stdio.h> +#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; + PGnotify* notify; + + 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); + } + + if (data->exec("LISTEN TBL2") != PGRES_COMMAND_OK) { + fprintf(stderr,"LISTEN command failed\n"); + delete data; + 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; + } + } + + /* close the connection to the database and cleanup */ + delete data; +} diff --git a/src/interfaces/libpq++/examples/testlibpq2.sql b/src/interfaces/libpq++/examples/testlibpq2.sql new file mode 100644 index 0000000000..f9c7410932 --- /dev/null +++ b/src/interfaces/libpq++/examples/testlibpq2.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/testlibpq3.cc b/src/interfaces/libpq++/examples/testlibpq3.cc new file mode 100644 index 0000000000..1146dffac9 --- /dev/null +++ b/src/interfaces/libpq++/examples/testlibpq3.cc @@ -0,0 +1,131 @@ +/* + * 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) + + * + */ +#include <stdio.h> +#include "libpq++.H" +extern "C" { +#include "utils/geo-decls.h" /* for the POLYGON type */ +} + +main() +{ + char* dbName; + int nFields; + int i,j; + int i_fnum, d_fnum, p_fnum; + + /* 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); + } + + /* start a transaction block */ + if (data->exec("BEGIN") != PGRES_COMMAND_OK) { + fprintf(stderr,"BEGIN command failed\n"); + delete data; + 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; + 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; + 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); + } + + /* 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/testlibpq3.sql b/src/interfaces/libpq++/examples/testlibpq3.sql new file mode 100644 index 0000000000..f024c0b071 --- /dev/null +++ b/src/interfaces/libpq++/examples/testlibpq3.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/testlibpq4.cc b/src/interfaces/libpq++/examples/testlibpq4.cc new file mode 100644 index 0000000000..9d5ca3ec76 --- /dev/null +++ b/src/interfaces/libpq++/examples/testlibpq4.cc @@ -0,0 +1,69 @@ +/* + * testlibpq4.cc + * Test the C++ version of LIBPQ, the POSTGRES frontend library. + * tests the copy in features + * + */ +#include <stdio.h> +#include "libpq++.H" + +#define DEBUG printf("Got here %d\n", __LINE__); +main() +{ + char* dbName; + int nFields; + int i,j; + + /* 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; + + 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); + } + + /* start a transaction block */ + if(data->exec("BEGIN") != PGRES_COMMAND_OK) { + fprintf(stderr,"BEGIN command failed\n"); + delete data; + 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); + } + + if (data->exec("COPY foo FROM STDIN") != PGRES_COMMAND_OK) { + fprintf(stderr,"COPY foo FROM STDIN\n"); + delete data; + exit(1); + } + + 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/testlo.cc b/src/interfaces/libpq++/examples/testlo.cc new file mode 100644 index 0000000000..be3459794f --- /dev/null +++ b/src/interfaces/libpq++/examples/testlo.cc @@ -0,0 +1,63 @@ +/*------------------------------------------------------------------------- + * + * lotest.cc-- + * test using large objects with libpq + * + * Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * $Header: /cvsroot/pgsql/src/interfaces/libpq++/examples/Attic/testlo.cc,v 1.1.1.1 1996/07/09 06:22:19 scrappy Exp $ + * + *------------------------------------------------------------------------- + */ +#include <stdio.h> +#include "libpq++.H" +extern "C" { +#include "libpq/libpq-fs.h" +} + +int +main(int argc, char **argv) +{ + char *in_filename, *out_filename; + char *database; + Oid lobjOid; + PGenv env; + PGlobj *object; + + if (argc < 4 || argc > 5) { + fprintf(stderr, "Usage: %s database_name in_filename out_filename [oid]\n", + argv[0]); + exit(1); + } + + database = argv[1]; + in_filename = argv[2]; + 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])); + } + + /* 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); + } + + 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; +} diff --git a/src/interfaces/libpq++/libpq++.H b/src/interfaces/libpq++/libpq++.H new file mode 100644 index 0000000000..9b3e173900 --- /dev/null +++ b/src/interfaces/libpq++/libpq++.H @@ -0,0 +1,173 @@ +/*------------------------------------------------------------------------- + * + * 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.1.1 1996/07/09 06:22:18 scrappy Exp $ + * + *------------------------------------------------------------------------- + */ + +#ifndef LIBPQXX_H +#define LIBPQXX_H + +#include <stdio.h> +#include <strings.h> + +extern "C" { +#include "libpq-fe.h" +#include "fe-auth.h" +} + +// **************************************************************** +// +// PGenv - the environment for setting up a connection to postgres +// +// **************************************************************** +class PGenv { + friend class PGconnection; + char* pgauth; + char* pghost; + char* pgport; + char* pgoption; + char* pgtty; +public: + PGenv(); // default ctor will use reasonable defaults + // will use environment variables PGHOST, PGPORT, + // PGOPTION, PGTTY + PGenv(char* auth, char* host, char* port, char* option, char* tty); + void setValues(char* auth, char* host, char* port, char* option, char* tty); + ~PGenv(); +}; + +// **************************************************************** +// +// PGconnection - a connection made to a postgres backend +// +// **************************************************************** +class PGconnection { + friend class PGdatabase; + friend class PGlobj; + PGenv* env; + PGconn* conn; + PGresult* result; + + char errorMessage[ERROR_MSG_LENGTH]; +public: + PGconnection(); // use reasonable defaults + PGconnection(PGenv* env, char* dbName); // connect to the database with + // given environment and database name + ConnStatusType status(); + char* errormessage() {return errorMessage;}; + + // returns the database name of the connection + char* dbName() {return PQdb(conn);}; + + ExecStatusType exec(char* query); // send a query to the backend + PGnotify* notifies() {exec(" "); return PQnotifies(conn);}; + ~PGconnection(); // close connection and clean up +protected: + ConnStatusType connect(PGenv* env, char* dbName); +}; + +// **************************************************************** +// +// PGdatabase - a class for accessing databases +// +// **************************************************************** +class PGdatabase : public PGconnection { +public: + PGdatabase() : PGconnection() {}; // use reasonable defaults + // connect to the database with + PGdatabase(PGenv* env, char* dbName) : PGconnection(env, dbName) {}; + // query result access + int ntuples() + {return PQntuples(result);}; + int nfields() + {return PQnfields(result);}; + char* fieldname(int field_num) + {return PQfname(result, field_num);}; + int fieldnum(char* field_name) + {return PQfnumber(result, field_name);}; + Oid fieldtype(int field_num) + {return PQftype(result, field_num);}; + Oid fieldtype(char* field_name) + {return PQftype(result, fieldnum(field_name));}; + int2 fieldsize(int field_num) + {return PQfsize(result, field_num);}; + int2 fieldsize(char* field_name) + {return PQfsize(result, fieldnum(field_name));}; + char* getvalue(int tup_num, int field_num) + {return PQgetvalue(result, tup_num, field_num);}; + char* getvalue(int tup_num, char* field_name) + {return PQgetvalue(result, tup_num, fieldnum(field_name));}; + int getlength(int tup_num, int field_num) + {return PQgetlength(result, tup_num, field_num);}; + int getlength(int tup_num, char* field_name) + {return PQgetlength(result, tup_num, fieldnum(field_name));}; + void printtuples(FILE *out, int fillAlign, char *fieldSep, + int printHeader, int quiet) + {PQdisplayTuples(result, out, fillAlign, fieldSep, printHeader, quiet);}; + // copy command related access + int getline(char* string, int length) + {return PQgetline(conn, string, length);}; + void putline(char* string) + {PQputline(conn, string);}; + int endcopy() + {return PQendcopy(conn);}; + ~PGdatabase() {}; // close connection and clean up +}; + +// **************************************************************** +// +// PGlobj - a class for accessing Large Object in a database +// +// **************************************************************** +class PGlobj : public PGconnection { + int fd; + Oid object; +public: + PGlobj(); // use reasonable defaults and create large object + PGlobj(Oid lobjId); // use reasonable defaults and open large object + PGlobj(PGenv* env, char* dbName); // create large object + PGlobj(PGenv* env, char* dbName, Oid lobjId); // open large object + int read(char* buf, int len) + {return lo_read(conn, fd, buf, len);}; + int write(char* buf, int len) + {return lo_write(conn, fd, buf, len);}; + int lseek(int offset, int whence) + {return lo_lseek(conn, fd, offset, whence);}; + int tell() + {return lo_tell(conn, fd);}; + int unlink(); + int import(char* filename); + int export(char* filename); + ~PGlobj(); // close connection and clean up +}; + +// +// 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" + +// buffer size +#define BUFSIZE 1024 + +#endif /* LIBPQXX_H */ diff --git a/src/interfaces/libpq++/man/libpq++.3 b/src/interfaces/libpq++/man/libpq++.3 new file mode 100644 index 0000000000..ebca7ab7bb --- /dev/null +++ b/src/interfaces/libpq++/man/libpq++.3 @@ -0,0 +1,434 @@ +.\" +.\" POSTGRES95 Data Base Management System +.\" +.\" Copyright (c) 1994-5 Regents of the University of California +.\" +.\" POSTGRES Data Base Management System +.\" Copyright (c) 1988,1994 Regents of the University of California +.\" +.\" Permission to use, copy, modify, and distribute this software and its +.\" documentation for any purpose, without fee, and without a written agreement +.\" is hereby granted, provided that the above copyright notice and this +.\" paragraph and the following two paragraphs appear in all copies. +.\" +.\" IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR +.\" DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING +.\" LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS +.\" DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE +.\" POSSIBILITY OF SUCH DAMAGE. +.\" +.\" THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, +.\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY +.\" AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS +.\" ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO +.\" PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. +.\" +.\" +.\" $Id: libpq++.3,v 1.1.1.1 1996/07/09 06:22:19 scrappy Exp $ +.\" +.\" ------------------------------------------------------------------ +.\" .(l, .)l +.\" fake "-me"-style lists +.de (l +.nf +.ie '\\$1'M' .in +0n +.el .in +5n +.. +.de )l +.fi +.in +.. +.\" .(C, .)C +.\" constant-width font blocks +.de (C +.ft C +.(b +.(l \\$1 +.sp +.. +.de )C +.sp +.)l +.)b +.ft R +.. +.\" ------------------------------------------------------------------ +.de SE +.nr si 0 +.nr so 0 +.nr $0 0 +.nr $i \\n(si*\\n($0 +.in \\n($i+\\n(po +.. +.\" ------------------------------------------------------------------ +.de SP +.he '\fB\\$1 (\\$2)'\\$3'\\$1 (\\$2)\fR' +.. +.\" ------------------------------------------------------------------ +.de SS +.PP +.B \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 +.PP +.. +.\" ------------------------------------------------------------------ +.SB +.ds II \s-1INGRES\s0 +.ds PG \s-1POSTGRES95\s0 +.ds UU \s-1UNIX\s0 +.ds PQ \s-1POSTQUEL\s0 +.ds LI \s-1LIBPQ++\s0 +.ds PV 4.2 +.SB +.TH INTRODUCTION LIBPQ++ 07/24/95 +.XA 0 "Libpq++" +.BH "LIBPQ++" +.SH DESCRIPTION +\*(LI is the C++ API to \*(PG. \*(LI is a set of classes which allow +client programs to connect to the \*(PG backend server. These connections +come in two forms: a Database Class and a Large Object class. +.PP +The Database Class is intended for manipulating a database. You can +send all sorts of SQL queries to the \*(PG backend server and retrieve +the responses of the server. +.PP +The Large Object Class is intended for manipulating a large object +in a database. Although a Large Object instance can send normal +queries to the \*(PG backend server it is only intended for simple +queries that do not return any data. A large object should be seen +as a file stream. In future it should behave much like the C++ file +streams +.IR cin , +.IR cout +and +.IR cerr . +This version of the documentation is based on the C library. Three +short programs are listed at the end of this section as examples of +\*(LI programming (though not necessarily of good programming). +.PP +There are several examples of \*(LI applications in the following +directory: +.(C +\&.../src/libpq++/examples +.)C +.XA 1 "Control and Initialization" +.SH "CONTROL AND INITIALIZATION" +.XA 2 "Environment Variables" +.SS "Environment Variables" +The following environment variables can be used to set up default +values for an environment and to avoid hard-coding database names into +an application program: +.TP 15n +.BR PGDATABASE +sets the default \*(PG database name. +.TP 15n +.BR PGHOST +sets the default server name. +.TP 15n +.BR PGOPTIONS +sets additional runtime options for the \*(PG backend. +.TP 15n +.BR PGPORT +sets the default communication port with the \*(PG backend. +.TP 15n +.BR PGTTY +sets the file or tty on which debugging messages from the backend server +are displayed. +.TP 15n +.BR PGREALM +sets the +.IR Kerberos +realm to use with \*(PG, if it is different from the local realm. If +.SM PGREALM +is set, \*(PG applications will attempt authentication with servers +for this realm and use separate ticket files to avoid conflicts with +local ticket files. This environment variable is only used if +.IR Kerberos +authentication is enabled. +.TP 15n +.BR PGAUTH +sets the type of authentication which should be used. Currently +only +.IR unauth , +.IR krb4 , +and +.IR krb5 . +are supported. Depending on whether you compiled in support for those. +.XA 1 "Database Connection Functions" +.SH "DATABASE ENVIRONMENT CLASS: PGenv" +The database environment class provides C++ objects for manipulating the +above environment variables. +.TP 15n +.BR PGenv +Create an environment for the running program. +.(C +PGenv() +PGenv(char* auth, char* host, char* port, char* option, char* tty) +.)C +The first form of this object's constructor sets up the defaults for +the program from the environment variables listed above. +The second allows the programmer to hardcode the values into the program. +The values of the second form relate directly to the environment variables +above. +.SH "DATABASE CLASS: PGdatabase" +The database class is a provides C++ objects that have a connection +to a backend server. To create such an object one first need +the apropriate environment for the backend to access. +The following constructors deal with making a connection to a backend +server from a C++ program. +.TP 15n +.BR PGdatabase +Make a new connection to a backend database server. +.(C +PGdatabase(PGenv *env, char *dbName); +.)C +After a PGdatabase has been created it should be checked to make sure +the connection to the database succeded before sending +queries to the object. This can easily be done by +retrieving the current status of the PGdatabase object with the +.IR status +command. +.BR PGdatabase::status +Returns the status of the PGdatabase object. + +.(C +ConnStatus PGdatabase::status() +.)C + +the following values are allowed + +.(C +CONNECTION_OK +CONNECTION_BAD +.)C + +.XA 1 "Query Execution Functions" +.SH "QUERY EXECUTION FUNCTIONS" +.TP 15n +.BR PGdatabase::exec +Submits a query to \*(PG and returns result status. In case of an error +.IR PGdatabase::errormessage +can be used to get more information on the error. +.(C +void +ExecStatusType PGdatabase::exec(char *query); +.)C +The following status results can be expected. +.(C +PGRES_EMPTY_QUERY, +PGRES_COMMAND_OK, /* the query was a command */ +PGRES_TUPLES_OK, /* the query successfully returned tuples */ +PGRES_COPY_OUT, +PGRES_COPY_IN, +PGRES_BAD_RESPONSE, /* an unexpected response was received */ +PGRES_NONFATAL_ERROR, +PGRES_FATAL_ERROR +.)C +.IP +If the result status is PGRES_TUPLES_OK, then the following routines can +be used to retrieve the tuples returned by the query. +.IP +.BR PGdatabase::ntuples +returns the number of tuples (instances) in the query result. +.(C +int PGdatabase::ntuples(); +.)C +.BR PGdatabase::nfields +returns the number of fields (attributes) in the query result. +.(C +int PGdatabase::nfields(); +.)C +.BR PGdatabase::fieldname +returns the field (attribute) name associated with the given field index. +Field indices start at 0. +.(C +char* PGdatabase::fieldname(int field_index); +.)C +.BR PGdatabase::fieldnum +returns the field (attribute) index associated with the given field name. +.(C +int PGdatabase::fieldnum(char* field_name); +.)C +.BR PGdatabase::fieldtype +returns the field type of associated with the given field index or name. +The integer returned is an internal coding of the type. Field indices start +at 0. +.(C +Oid PGdatabase::fieldtype(int field_index); +Oid PGdatabase::fieldtype(char* field_name); +.)C +.BR PGdatabase::fieldsize +returns the size in bytes of the field associated with the given field +index or name. If the size returned is -1, the field is a variable length +field. Field indices start at 0. +.(C +int2 PGdatabase::fieldsize(int field_index); +int2 PGdatabase::fieldsize(char* field_name); +.)C +.BR PGdatabase::getvalue +returns the field (attribute) value. For most queries, the values +returned by +.IR PGdatabase::getvalue +is a null-terminated ASCII string representation +of the attribute value. If the query was a result of a +.BR BINARY +cursor, then the values returned by +.IR PGdatabase::getvalue +is the binary representation of the type in the internal format of the +backend server. It is the programmer's responsibility to cast and +convert the data to the correct C++ type. The value return by +.IR PGdatabase::getvalue +points to storage that is part of the PGdatabase structure. One must +explicitly copy the value into other storage if it is to be used past +the next query. +.(C +char* PGdatabase::getvalue(int tup_num, int field_index); +char* PGdatabase::getvalue(int tup_num, char* field_name); +.)C +.BR PGdatabase::getlength +returns the length of a field (attribute) in bytes. If the field +is a +.IR "struct varlena" , +the length returned here does +.BR not +include the size field of the varlena, i.e., it is 4 bytes less. +.(C +int PGdatabase::getlength(int tup_num, int field_index); +int PGdatabase::getlength(int tup_num, char* field_name); +.)C +.BR PGdatabase::printtuples +prints out all the tuples and, optionally, the attribute names to the +specified output stream. +.(C +void PGdatabase::printtuples( + FILE* fout, /* output stream */ + int printAttName,/* print attribute names or not*/ + int terseOutput, /* delimiter bars or not?*/ + int width /* width of column, variable width if 0*/ + ); +.)C +.XA 1 "Asynchronous Notification" +.SH "ASYNCHRONOUS NOTIFICATION" +\*(PG supports asynchronous notification via the +.IR LISTEN +and +.IR NOTIFY +commands. A backend registers its interest in a particular relation +with the LISTEN command. All backends that are listening on a +particular relation will be notified asynchronously when a NOTIFY of +that relation name is executed by another backend. No additional +information is passed from the notifier to the listener. Thus, +typically, any actual data that needs to be communicated is transferred +through the relation. +.PP +\*(LI applications are notified whenever a connected backend has +received an asynchronous notification. However, the communication from +the backend to the frontend is not asynchronous. The \*(LI application +must poll the backend to see if there is any pending notification +information. After the execution of a query, a frontend may call +.IR PGdatabase::notifies +to see if any notification data is currently available from the backend. +.TP 15n +.BR PGdatabase::notifies +returns the notification from a list of unhandled notifications from the +backend. Returns NULL if there is no pending notifications from the +backend. +.IR PGdatabase::notifies +behaves like the popping of a stack. Once a notification is returned +from +.IR PGdatabase::notifies, +it is considered handled and will be removed from the list of +notifications. +.(C +PGnotify* PGdatabase::notifies() +.)C +.PP +The second sample program gives an example of the use of asynchronous +notification. +.XA 1 "Functions Associated with the COPY Command" +.SH "FUNCTIONS ASSOCIATED WITH THE COPY COMMAND" +The +.IR copy +command in \*(PG has options to read from or write to the network +connection used by \*(LI. Therefore, functions are necessary to +access this network connection directly so applications may take full +advantage of this capability. +.TP 15n +.BR PGdatabase::getline +Reads a newline-terminated line of characters (transmitted by the +backend server) into a buffer +.IR string +of size +.IR length . +Like +.IR fgets (3), +this routine copies up to +.IR length "-1" +characters into +.IR string . +It is like +.IR gets (3), +however, in that it converts the terminating newline into a null +character. +.IP +.IR PGdatabase::getline +returns EOF at EOF, 0 if the entire line has been read, and 1 if the +buffer is full but the terminating newline has not yet been read. +.IP +Notice that the application must check to see if a new line consists +of the single character \*(lq.\*(rq, which indicates that the backend +server has finished sending the results of the +.IR copy +command. Therefore, if the application ever expects to receive lines +that are more than +.IR length "-1" +characters long, the application must be sure to check the return +value of +.IR PGdatabase::getline +very carefully. +.IP +.(C +int PGdatabase::getline(char* string, int length) +.)C +.TP 15n +.BR PGdatabase::putline +Sends a null-terminated +.IR string +to the backend server. +.IP +The application must explicitly send the single character \*(lq.\*(rq +to indicate to the backend that it has finished sending its data. +.(C +void PGdatabase::putline(char* string) +.)C +.TP 15n +.BR PGdatabase::endcopy +Syncs with the backend. This function waits until the backend has +finished processing the copy. It should either be issued when the +last string has been sent to the backend using +.IR PGdatabase::putline +or when the last string has been received from the backend using +.IR PGdatabase::getline . +It must be issued or the backend may get \*(lqout of sync\*(rq with +the frontend. Upon return from this function, the backend is ready to +receive the next query. +.IP +The return value is 0 on successful completion, nonzero otherwise. +.(C +int PGdatabase::endcopy() +.)C +As an example: +.(C +PGdatabase data; +data.exec("create table foo (a int4, b char16, d float8)"); +data.exec("copy foo from stdin"); +data.putline("3\etHello World\et4.5\en"); +data.putline("4\etGoodbye World\et7.11\en"); +\&... +data.putline(".\en"); +data.endcopy(); +.)C +.SH BUGS +The query buffer is 8192 bytes long, and queries over that length will +be silently truncated. +.bp +The PGlobj class is largely untested. Use with caution. diff --git a/src/interfaces/libpq++/pgconnection.cc b/src/interfaces/libpq++/pgconnection.cc new file mode 100644 index 0000000000..777a12e8e7 --- /dev/null +++ b/src/interfaces/libpq++/pgconnection.cc @@ -0,0 +1,94 @@ +/*------------------------------------------------------------------------- + * + * FILE + * pgconnection.cc + * + * DESCRIPTION + * 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 $ + * + *------------------------------------------------------------------------- + */ + +#include "libpq++.H" + +// default constructor +// checks environment variable for database name +PGconnection::PGconnection() +{ + char* name; + PGenv* newenv; + + conn = NULL; + result = NULL; + errorMessage[0] = '\0'; + + newenv = new PGenv(); // use reasonable defaults for the environment + if (!(name = getenv(ENV_DEFAULT_DBASE))) + return; + connect(newenv, name); +} + +// constructor -- for given environment and database name +PGconnection::PGconnection(PGenv* env, char* dbName) +{ + conn = NULL; + result = NULL; + errorMessage[0] = '\0'; + connect(env, dbName); +} + +// destructor - closes down the connection and cleanup +PGconnection::~PGconnection() +{ + if (result) PQclear(result); + if (conn) PQfinish(conn); +} + +// PGconnection::connect +// establish a connection to a backend +ConnStatusType +PGconnection::connect(PGenv* newenv, 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; + else + return status(); +} + +// PGconnection::status -- return connection or result status +ConnStatusType +PGconnection::status() +{ + return PQstatus(conn); +} + +// PGconnection::exec -- send a query to the backend +ExecStatusType +PGconnection::exec(char* query) +{ + if (result) + PQclear(result); + + result = PQexec(conn, query); + if (result) + return PQresultStatus(result); + else { + strcpy(errorMessage, PQerrorMessage(conn)); + return PGRES_FATAL_ERROR; + } +} diff --git a/src/interfaces/libpq++/pgenv.cc b/src/interfaces/libpq++/pgenv.cc new file mode 100644 index 0000000000..aab4f213eb --- /dev/null +++ b/src/interfaces/libpq++/pgenv.cc @@ -0,0 +1,109 @@ +/*------------------------------------------------------------------------- + * + * FILE + * PGenv.cc + * + * DESCRIPTION + * PGenv is the environment for setting up a connection to a + * postgres backend, captures the host, port, tty, options and + * authentication type. + * + * NOTES + * Currently under construction. + * + * Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * $Header: /cvsroot/pgsql/src/interfaces/libpq++/Attic/pgenv.cc,v 1.1.1.1 1996/07/09 06:22:18 scrappy Exp $ + * + *------------------------------------------------------------------------- + */ + +#include <stdlib.h> +#include "libpq++.H" + +#define DefaultAuth DEFAULT_CLIENT_AUTHSVC +#define DefaultPort POSTPORT + +// default constructor for PGenv +// checks the environment variables +PGenv::PGenv() +{ + char* temp; + + pgauth = NULL; + pghost = NULL; + pgport = NULL; + pgoption = NULL; + pgtty = NULL; + + setValues(getenv(ENV_DEFAULT_AUTH), getenv(ENV_DEFAULT_HOST), + getenv(ENV_DEFAULT_PORT), getenv(ENV_DEFAULT_OPTION), + getenv(ENV_DEFAULT_TTY)); +} + +// constructor for given environment +PGenv::PGenv(char* auth, char* host, char* port, char* option, char* tty) +{ + pgauth = NULL; + pghost = NULL; + pgport = NULL; + pgoption = NULL; + pgtty = NULL; + + 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) +{ + 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); +} + +// default destrutor +// frees allocated memory for internal structures +PGenv::~PGenv() +{ + if (pgauth) + free(pgauth); + if (pghost) + free(pghost); + if (pgport) + free(pgport); + if (pgoption) + free(pgoption); + if (pgtty) + free(pgtty); +} diff --git a/src/interfaces/libpq++/pglobject.cc b/src/interfaces/libpq++/pglobject.cc new file mode 100644 index 0000000000..20c7ad5e22 --- /dev/null +++ b/src/interfaces/libpq++/pglobject.cc @@ -0,0 +1,152 @@ + +/*------------------------------------------------------------------------- + * + * FILE + * pglobject.cc + * + * DESCRIPTION + * implementation of the PGlobj class. + * PGlobj 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.1.1.1 1996/07/09 06:22:18 scrappy Exp $ + * + *------------------------------------------------------------------------- + */ +#include "libpq++.H" + +extern "C" { +#include "libpq/libpq-fs.h" +} + +// 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); + +} + +// 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); +} + +// 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); +} + +// 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); +} + +// 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; + } +} + +// 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; +} + +// 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; + } + + // 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; +} + +// default destructor -- closes large object +PGlobj::~PGlobj() { + if (fd >= 0) + lo_close(conn, fd); +} |
