diff -Nur postgresql-8.0.3-orig/src/backend/libpq/be-fsstubs.c postgresql-8.0.3/src/backend/libpq/be-fsstubs.c --- postgresql-8.0.3-orig/src/backend/libpq/be-fsstubs.c 2004-12-31 13:59:50.000000000 -0800 +++ postgresql-8.0.3/src/backend/libpq/be-fsstubs.c 2005-09-18 17:22:17.000000000 -0700 @@ -233,6 +233,34 @@ PG_RETURN_INT32(status); } + +Datum +lo_lseek64(PG_FUNCTION_ARGS) +{ + int32 fd = PG_GETARG_INT32(0); + int64 offset = PG_GETARG_INT64(1); + int32 whence = PG_GETARG_INT32(2); + MemoryContext currentContext; + int64 status; + + if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL) + { + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("invalid large-object descriptor: %d", fd))); + PG_RETURN_INT64(-1); + } + + Assert(fscxt != NULL); + currentContext = MemoryContextSwitchTo(fscxt); + + status = inv_seek64(cookies[fd], offset, whence); + + MemoryContextSwitchTo(currentContext); + + PG_RETURN_INT64(status); +} + Datum lo_creat(PG_FUNCTION_ARGS) { @@ -283,6 +311,28 @@ PG_RETURN_INT32(inv_tell(cookies[fd])); } + +Datum +lo_tell64(PG_FUNCTION_ARGS) +{ + int32 fd = PG_GETARG_INT32(0); + + if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL) + { + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("invalid large-object descriptor: %d", fd))); + PG_RETURN_INT64(-1); + } + + /* + * We assume we do not need to switch contexts for inv_tell. That is + * true for now, but is probably more than this module ought to + * assume... + */ + PG_RETURN_INT64(inv_tell(cookies[fd])); +} + Datum lo_unlink(PG_FUNCTION_ARGS) { diff -Nur postgresql-8.0.3-orig/src/backend/storage/large_object/inv_api.c postgresql-8.0.3/src/backend/storage/large_object/inv_api.c --- postgresql-8.0.3-orig/src/backend/storage/large_object/inv_api.c 2004-12-31 14:00:59.000000000 -0800 +++ postgresql-8.0.3/src/backend/storage/large_object/inv_api.c 2005-09-18 19:28:24.000000000 -0700 @@ -255,11 +255,11 @@ * NOTE: LOs can contain gaps, just like Unix files. We actually return * the offset of the last byte + 1. */ -static uint32 +static uint64 inv_getsize(LargeObjectDesc *obj_desc) { bool found = false; - uint32 lastbyte = 0; + uint64 lastbyte = 0; ScanKeyData skey[1]; IndexScanDesc sd; HeapTuple tuple; @@ -298,7 +298,7 @@ heap_tuple_untoast_attr((varattrib *) datafield); pfreeit = true; } - lastbyte = data->pageno * LOBLKSIZE + getbytealen(datafield); + lastbyte = (uint64) data->pageno * LOBLKSIZE + getbytealen(datafield); if (pfreeit) pfree(datafield); break; @@ -353,15 +353,55 @@ return obj_desc->offset; } +int64 +inv_seek64(LargeObjectDesc *obj_desc, int64 offset, int whence) +{ + Assert(PointerIsValid(obj_desc)); + + switch (whence) + { + case SEEK_SET: + if (offset < 0) + elog(ERROR, "invalid seek offset: " INT64_FORMAT, offset); + obj_desc->offset = offset; + break; + case SEEK_CUR: + if (offset < 0 && obj_desc->offset < ((uint64) (-offset))) + elog(ERROR, "invalid seek offset: " INT64_FORMAT, offset); + obj_desc->offset += offset; + break; + case SEEK_END: + { + uint64 size = inv_getsize(obj_desc); + + if (offset < 0 && size < ((uint64) (-offset))) + elog(ERROR, "invalid seek offset: " INT64_FORMAT, offset); + obj_desc->offset = size + offset; + } + break; + default: + elog(ERROR, "invalid whence: %d", whence); + } + return obj_desc->offset; +} + +int64 +inv_tell64(LargeObjectDesc *obj_desc) +{ + Assert(PointerIsValid(obj_desc)); + + return obj_desc->offset; +} + int inv_read(LargeObjectDesc *obj_desc, char *buf, int nbytes) { int nread = 0; - int n; - int off; + int64 n; + int64 off; int len; int32 pageno = (int32) (obj_desc->offset / LOBLKSIZE); - uint32 pageoff; + uint64 pageoff; ScanKeyData skey[2]; IndexScanDesc sd; HeapTuple tuple; @@ -400,7 +440,7 @@ * there may be missing pages if the LO contains unwritten * "holes". We want missing sections to read out as zeroes. */ - pageoff = ((uint32) data->pageno) * LOBLKSIZE; + pageoff = ((uint64) data->pageno) * LOBLKSIZE; if (pageoff > obj_desc->offset) { n = pageoff - obj_desc->offset; diff -Nur postgresql-8.0.3-orig/src/include/catalog/pg_proc.h postgresql-8.0.3/src/include/catalog/pg_proc.h --- postgresql-8.0.3-orig/src/include/catalog/pg_proc.h 2004-12-31 14:03:25.000000000 -0800 +++ postgresql-8.0.3/src/include/catalog/pg_proc.h 2005-09-17 23:18:47.000000000 -0700 @@ -1224,10 +1224,14 @@ DESCR("large object read"); DATA(insert OID = 955 ( lowrite PGNSP PGUID 12 f f t f v 2 23 "23 17" _null_ lowrite - _null_ )); DESCR("large object write"); +DATA(insert OID = 0 ( lo_lseek64 PGNSP PGUID 12 f f t f v 3 20 "23 20 23" _null_ lo_lseek64 - _null_ )); +DESCR("large object seek (64bit)"); DATA(insert OID = 956 ( lo_lseek PGNSP PGUID 12 f f t f v 3 23 "23 23 23" _null_ lo_lseek - _null_ )); DESCR("large object seek"); DATA(insert OID = 957 ( lo_creat PGNSP PGUID 12 f f t f v 1 26 "23" _null_ lo_creat - _null_ )); DESCR("large object create"); +DATA(insert OID = 0 ( lo_tell64 PGNSP PGUID 12 f f t f v 1 20 "23" _null_ lo_tell64 - _null_ )); +DESCR("large object position (64bit)"); DATA(insert OID = 958 ( lo_tell PGNSP PGUID 12 f f t f v 1 23 "23" _null_ lo_tell - _null_ )); DESCR("large object position"); diff -Nur postgresql-8.0.3-orig/src/include/libpq/be-fsstubs.h postgresql-8.0.3/src/include/libpq/be-fsstubs.h --- postgresql-8.0.3-orig/src/include/libpq/be-fsstubs.h 2004-12-31 14:03:32.000000000 -0800 +++ postgresql-8.0.3/src/include/libpq/be-fsstubs.h 2005-09-17 23:18:47.000000000 -0700 @@ -32,6 +32,8 @@ extern Datum lo_lseek(PG_FUNCTION_ARGS); extern Datum lo_tell(PG_FUNCTION_ARGS); +extern Datum lo_lseek64(PG_FUNCTION_ARGS); +extern Datum lo_tell64(PG_FUNCTION_ARGS); extern Datum lo_unlink(PG_FUNCTION_ARGS); /* diff -Nur postgresql-8.0.3-orig/src/include/storage/large_object.h postgresql-8.0.3/src/include/storage/large_object.h --- postgresql-8.0.3-orig/src/include/storage/large_object.h 2004-12-31 14:03:42.000000000 -0800 +++ postgresql-8.0.3/src/include/storage/large_object.h 2005-09-17 23:18:47.000000000 -0700 @@ -33,7 +33,7 @@ { Oid id; /* LO's identifier */ SubTransactionId subid; /* owning subtransaction ID */ - uint32 offset; /* current seek pointer */ + uint64 offset; /* current seek pointer */ int flags; /* locking info, etc */ /* flag bits: */ @@ -71,6 +71,8 @@ extern int inv_drop(Oid lobjId); extern int inv_seek(LargeObjectDesc *obj_desc, int offset, int whence); extern int inv_tell(LargeObjectDesc *obj_desc); +extern int64 inv_seek64(LargeObjectDesc *obj_desc, int64 offset, int whence); +extern int64 inv_tell64(LargeObjectDesc *obj_desc); extern int inv_read(LargeObjectDesc *obj_desc, char *buf, int nbytes); extern int inv_write(LargeObjectDesc *obj_desc, char *buf, int nbytes); diff -Nur postgresql-8.0.3-orig/src/interfaces/libpq/fe-lobj.c postgresql-8.0.3/src/interfaces/libpq/fe-lobj.c --- postgresql-8.0.3-orig/src/interfaces/libpq/fe-lobj.c 2004-12-31 14:03:50.000000000 -0800 +++ postgresql-8.0.3/src/interfaces/libpq/fe-lobj.c 2005-09-19 00:39:20.000000000 -0700 @@ -264,6 +264,61 @@ } /* + * lo_lseek64 + * change the current read or write location on a large object + * currently, only L_SET is a legal value for whence + * + */ + +int64 +lo_lseek64(PGconn *conn, int fd, int64 offset, int whence) +{ + PQArgBlock argv[3]; + PGresult *res; + int64 retval; + int result_len; + + if (conn->lobjfuncs == NULL) + { + if (lo_initialize(conn) < 0) + return -1; + } + + if (conn->lobjfuncs->fn_lo_lseek64 == 0) + { + printfPQExpBuffer(&conn->errorMessage, + libpq_gettext("cannot determine OID of function lo_lseek64\n")); + + return -1; + } + + argv[0].isint = 1; + argv[0].len = 4; + argv[0].u.integer = fd; + + argv[1].isint = 1; + argv[1].len = 8; + argv[1].u.ptr = (int *) &offset; + + argv[2].isint = 1; + argv[2].len = 4; + argv[2].u.integer = whence; + + res = PQfn(conn, conn->lobjfuncs->fn_lo_lseek64, + (int *)&retval, &result_len, 1, argv, 3); + if (PQresultStatus(res) == PGRES_COMMAND_OK) + { + PQclear(res); + return retval; + } + else + { + PQclear(res); + return -1; + } +} + +/* * lo_creat * create a new large object * the mode is a bitmask describing different attributes of the new object @@ -305,6 +360,53 @@ /* + * lo_tell64 + * returns the current seek location of the large object + * + */ + +int64 +lo_tell64(PGconn *conn, int fd) +{ + int64 retval; + PQArgBlock argv[1]; + PGresult *res; + int result_len; + + if (conn->lobjfuncs == NULL) + { + if (lo_initialize(conn) < 0) + return -1; + } + + if (conn->lobjfuncs->fn_lo_tell64 == 0) + { + printfPQExpBuffer(&conn->errorMessage, + libpq_gettext("cannot determine OID of function lo_tell64\n")); + + return -1; + } + + argv[0].isint = 1; + argv[0].len = 4; + argv[0].u.integer = fd; + + res = PQfn(conn, conn->lobjfuncs->fn_lo_tell64, + (int *) &retval, &result_len, 1, argv, 1); + if (PQresultStatus(res) == PGRES_COMMAND_OK) + { + PQclear(res); + return retval; + } + else + { + PQclear(res); + return -1; + } +} + + +/* * lo_tell * returns the current seek location of the large object * @@ -570,7 +672,9 @@ "'lo_creat', " "'lo_unlink', " "'lo_lseek', " + "'lo_lseek64', " "'lo_tell', " + "'lo_tell64', " "'loread', " "'lowrite') " "and pronamespace = (select oid from pg_catalog.pg_namespace " @@ -583,6 +687,8 @@ "or proname = 'lo_unlink' " "or proname = 'lo_lseek' " "or proname = 'lo_tell' " + "or proname = 'lo_lseek64' " + "or proname = 'lo_tell64' " "or proname = 'loread' " "or proname = 'lowrite'"; @@ -621,6 +727,10 @@ lobjfuncs->fn_lo_lseek = foid; else if (!strcmp(fname, "lo_tell")) lobjfuncs->fn_lo_tell = foid; + else if (!strcmp(fname, "lo_lseek64")) + lobjfuncs->fn_lo_lseek64 = foid; + else if (!strcmp(fname, "lo_tell64")) + lobjfuncs->fn_lo_tell64 = foid; else if (!strcmp(fname, "loread")) lobjfuncs->fn_lo_read = foid; else if (!strcmp(fname, "lowrite")) diff -Nur postgresql-8.0.3-orig/src/interfaces/libpq/fe-misc.c postgresql-8.0.3/src/interfaces/libpq/fe-misc.c --- postgresql-8.0.3-orig/src/interfaces/libpq/fe-misc.c 2004-12-31 14:03:50.000000000 -0800 +++ postgresql-8.0.3/src/interfaces/libpq/fe-misc.c 2005-09-18 19:26:58.000000000 -0700 @@ -223,6 +223,27 @@ conn->inCursor += 4; *result = (int) ntohl(tmp4); break; + case 8: + if (conn->inCursor + 8 > conn->inEnd) + return EOF; + else + { + int64 * i64res = (int64 *)result; + uint32 h32; + memcpy(&h32, conn->inBuffer + conn->inCursor, 4); + conn->inCursor += 4; + memcpy(&tmp4, conn->inBuffer + conn->inCursor, 4); + conn->inCursor += 4; +#ifdef INT64_IS_BUSTED + /* just lose the high half */ + *i64res = (int) ntohl(tmp4); +#else + *i64res = (int) ntohl(h32); + *i64res <<= 32; + *i64res |= (uint32) ntohl(tmp4); +#endif + } + break; default: pqInternalNotice(&conn->noticeHooks, "integer of size %lu not supported by pqGetInt", @@ -231,12 +252,23 @@ } if (conn->Pfdebug) - fprintf(conn->Pfdebug, "From backend (#%lu)> %d\n", (unsigned long) bytes, *result); + fprintf(conn->Pfdebug, "From backend (#%lu)> " INT64_FORMAT "\n", (unsigned long) bytes, (bytes == 8) ? *(int64 *)result : (int64)*result); return 0; } /* + * pqGetInt64 + * read an 8 byte integer and convert from network byte order + * to local byte order + */ +int +pqGetInt64(int64 *result, PGconn *conn) +{ + return pqGetInt((int *)result, 8, conn); +} + +/* * pqPutInt * write an integer of 2 or 4 bytes, converting from host byte order * to network byte order. @@ -272,6 +304,41 @@ return 0; } + +/* + * pqPutInt64 + * write an integer of 8 bytes, converting from host byte order + * to network byte order. + */ +int +pqPutInt64(int64 value, PGconn *conn) +{ + uint32 n32; + + /* High order half first, since we're doing MSB-first */ +#ifdef INT64_IS_BUSTED + /* don't try a right shift of 32 on a 32-bit word */ + n32 = (value < 0) ? -1 : 0; +#else + n32 = (uint32) (value >> 32); +#endif + n32 = htonl(n32); + if (pqPutMsgBytes((const char *) &n32, 4, conn)) + return EOF; + + /* Now the low order half */ + n32 = (uint32) value; + n32 = htonl(n32); + + if (pqPutMsgBytes((const char *) &n32, 4, conn)) + return EOF; + + if (conn->Pfdebug) + fprintf(conn->Pfdebug, "To backend (8#)> " INT64_FORMAT "\n", value); + + return 0; +} + /* * Make sure conn's output buffer can hold bytes_needed bytes (caller must * include already-stored data into the value!) diff -Nur postgresql-8.0.3-orig/src/interfaces/libpq/fe-protocol3.c postgresql-8.0.3/src/interfaces/libpq/fe-protocol3.c --- postgresql-8.0.3-orig/src/interfaces/libpq/fe-protocol3.c 2004-12-31 14:03:50.000000000 -0800 +++ postgresql-8.0.3/src/interfaces/libpq/fe-protocol3.c 2005-09-18 16:47:10.000000000 -0700 @@ -1233,11 +1233,24 @@ if (args[i].isint) { - if (pqPutInt(args[i].u.integer, args[i].len, conn)) + if (args[i].len <= 4) { - pqHandleSendFailure(conn); - return NULL; + if (pqPutInt(args[i].u.integer, args[i].len, conn)) + { + pqHandleSendFailure(conn); + return NULL; + } + } + else + { + if (pqPutInt64(*(int64 *)args[i].u.ptr, conn)) + { + pqHandleSendFailure(conn); + return NULL; + } } + + } else { diff -Nur postgresql-8.0.3-orig/src/interfaces/libpq/libpq-fe.h postgresql-8.0.3/src/interfaces/libpq/libpq-fe.h --- postgresql-8.0.3-orig/src/interfaces/libpq/libpq-fe.h 2004-12-31 14:03:50.000000000 -0800 +++ postgresql-8.0.3/src/interfaces/libpq/libpq-fe.h 2005-09-17 23:18:47.000000000 -0700 @@ -27,6 +27,7 @@ * such as Oid. */ #include "postgres_ext.h" +#include "postgres_fe.h" /* SSL type is needed here only to declare PQgetssl() */ #ifdef USE_SSL @@ -479,8 +480,10 @@ extern int lo_read(PGconn *conn, int fd, char *buf, size_t len); extern int lo_write(PGconn *conn, int fd, char *buf, size_t len); extern int lo_lseek(PGconn *conn, int fd, int offset, int whence); +extern int64 lo_lseek64(PGconn *conn, int fd, int64 offset, int whence); extern Oid lo_creat(PGconn *conn, int mode); extern int lo_tell(PGconn *conn, int fd); +extern int64 lo_tell64(PGconn *conn, int fd); extern int lo_unlink(PGconn *conn, Oid lobjId); extern Oid lo_import(PGconn *conn, const char *filename); extern int lo_export(PGconn *conn, Oid lobjId, const char *filename); diff -Nur postgresql-8.0.3-orig/src/interfaces/libpq/libpq-int.h postgresql-8.0.3/src/interfaces/libpq/libpq-int.h --- postgresql-8.0.3-orig/src/interfaces/libpq/libpq-int.h 2005-01-05 16:59:47.000000000 -0800 +++ postgresql-8.0.3/src/interfaces/libpq/libpq-int.h 2005-09-18 16:05:46.000000000 -0700 @@ -232,6 +232,8 @@ Oid fn_lo_unlink; /* OID of backend function lo_unlink */ Oid fn_lo_lseek; /* OID of backend function lo_lseek */ Oid fn_lo_tell; /* OID of backend function lo_tell */ + Oid fn_lo_lseek64; /* OID of backend function lo_lseek64 */ + Oid fn_lo_tell64; /* OID of backend function lo_tell64 */ Oid fn_lo_read; /* OID of backend function LOread */ Oid fn_lo_write; /* OID of backend function LOwrite */ } PGlobjfuncs; @@ -457,7 +459,9 @@ extern int pqGetnchar(char *s, size_t len, PGconn *conn); extern int pqPutnchar(const char *s, size_t len, PGconn *conn); extern int pqGetInt(int *result, size_t bytes, PGconn *conn); +extern int pqGetInt64(int64 *result, PGconn *conn); extern int pqPutInt(int value, size_t bytes, PGconn *conn); +extern int pqPutInt64(int64 value, PGconn *conn); extern int pqPutMsgStart(char msg_type, bool force_len, PGconn *conn); extern int pqPutMsgEnd(PGconn *conn); extern int pqReadData(PGconn *conn); diff -Nur postgresql-8.0.3-orig/src/test/examples/Makefile postgresql-8.0.3/src/test/examples/Makefile --- postgresql-8.0.3-orig/src/test/examples/Makefile 2005-03-25 10:18:41.000000000 -0800 +++ postgresql-8.0.3/src/test/examples/Makefile 2005-09-17 23:18:47.000000000 -0700 @@ -6,11 +6,11 @@ top_builddir = ../../.. include $(top_builddir)/src/Makefile.global -override CPPFLAGS := -I$(libpq_srcdir) $(CPPFLAGS) +override CPPFLAGS := -I$(libpq_srcdir) $(CPPFLAGS) -g override LDLIBS := $(libpq_pgport) $(LDLIBS) -PROGS = testlibpq testlibpq2 testlibpq3 testlibpq4 testlo +PROGS = testlibpq testlibpq2 testlibpq3 testlibpq4 testlo testlo64 all: $(PROGS) diff -Nur postgresql-8.0.3-orig/src/test/examples/testlo64.c postgresql-8.0.3/src/test/examples/testlo64.c --- postgresql-8.0.3-orig/src/test/examples/testlo64.c 1969-12-31 16:00:00.000000000 -0800 +++ postgresql-8.0.3/src/test/examples/testlo64.c 2005-09-19 00:52:16.000000000 -0700 @@ -0,0 +1,267 @@ +/*------------------------------------------------------------------------- + * + * testlo.c + * test using large objects with libpq + * + * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * $PostgreSQL: pgsql/src/test/examples/testlo.c,v 1.25 2004/12/31 22:03:58 pgsql Exp $ + * + *------------------------------------------------------------------------- + */ +#include +#include + +#include +#include +#include +#include + +#include "libpq-fe.h" +#include "libpq/libpq-fs.h" + +#define BUFSIZE 1024 + +/* + * importFile - + * import file "in_filename" into database as large object "lobjOid" + * + */ +static Oid +importFile(PGconn *conn, char *filename) +{ + Oid lobjId; + int lobj_fd; + char buf[BUFSIZE]; + int nbytes, + tmp; + int fd; + + /* + * open the file to be read in + */ + fd = open(filename, O_RDONLY, 0666); + if (fd < 0) + { /* error */ + fprintf(stderr, "can't open unix file\"%s\"\n", filename); + } + + /* + * create the large object + */ + lobjId = lo_creat(conn, INV_READ | INV_WRITE); + if (lobjId == 0) + fprintf(stderr, "can't create large object"); + + lobj_fd = lo_open(conn, lobjId, INV_WRITE); + + /* + * read in from the Unix file and write to the inversion file + */ + while ((nbytes = read(fd, buf, BUFSIZE)) > 0) + { + tmp = lo_write(conn, lobj_fd, buf, nbytes); + if (tmp < nbytes) + fprintf(stderr, "error while reading \"%s\"", filename); + } + + close(fd); + lo_close(conn, lobj_fd); + + return lobjId; +} + +static void +pickout(PGconn *conn, Oid lobjId, int64 start, int len) +{ + int lobj_fd; + char *buf; + int nbytes; + int nread; + + lobj_fd = lo_open(conn, lobjId, INV_READ); + if (lobj_fd < 0) + fprintf(stderr, "can't open large object %u", lobjId); + + if (lo_lseek64(conn, lobj_fd, start, SEEK_SET) < 0) + { + fprintf(stderr, "error lo_lseek64: %s\n", PQerrorMessage(conn)); + return; + } + + buf = malloc(len + 1); + + nread = 0; + while (len - nread > 0) + { + nbytes = lo_read(conn, lobj_fd, buf, len - nread); + buf[nbytes] = '\0'; + fprintf(stderr, ">>> %s", buf); + nread += nbytes; + if (nbytes <= 0) + break; /* no more data? */ + } + free(buf); + fprintf(stderr, "\n"); + lo_close(conn, lobj_fd); +} + +static void +overwrite(PGconn *conn, Oid lobjId, int64 start, int len) +{ + int lobj_fd; + char *buf; + int nbytes; + int nwritten; + int i; + + lobj_fd = lo_open(conn, lobjId, INV_READ); + if (lobj_fd < 0) + fprintf(stderr, "can't open large object %u", lobjId); + + lo_lseek64(conn, lobj_fd, start, SEEK_SET); + buf = malloc(len + 1); + + for (i = 0; i < len; i++) + buf[i] = 'X'; + buf[i] = '\0'; + + nwritten = 0; + while (len - nwritten > 0) + { + nbytes = lo_write(conn, lobj_fd, buf + nwritten, len - nwritten); + nwritten += nbytes; + if (nbytes <= 0) + { + fprintf(stderr, "\nWRITE FAILED!\n"); + break; + } + } + free(buf); + fprintf(stderr, "\n"); + lo_close(conn, lobj_fd); +} + + +/* + * exportFile - + * export large object "lobjOid" to file "out_filename" + * + */ +static void +exportFile(PGconn *conn, Oid lobjId, char *filename) +{ + int lobj_fd; + char buf[BUFSIZE]; + int nbytes, + tmp; + int fd; + + /* + * create an inversion "object" + */ + lobj_fd = lo_open(conn, lobjId, INV_READ); + if (lobj_fd < 0) + fprintf(stderr, "can't open large object %u", lobjId); + + /* + * open the file to be written to + */ + fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666); + if (fd < 0) + { /* error */ + fprintf(stderr, "can't open unix file\"%s\"", + filename); + } + + /* + * read in from the Unix file and write to the inversion file + */ + while ((nbytes = lo_read(conn, lobj_fd, buf, BUFSIZE)) > 0) + { + tmp = write(fd, buf, nbytes); + if (tmp < nbytes) + { + fprintf(stderr, "error while writing \"%s\"", + filename); + } + } + + lo_close(conn, lobj_fd); + close(fd); + + return; +} + +static void +exit_nicely(PGconn *conn) +{ + PQfinish(conn); + exit(1); +} + +int +main(int argc, char **argv) +{ + char *in_filename, + *out_filename; + char *database; + Oid lobjOid; + PGconn *conn; + PGresult *res; + + if (argc != 4) + { + fprintf(stderr, "Usage: %s database_name in_filename out_filename\n", + argv[0]); + exit(1); + } + + database = argv[1]; + in_filename = argv[2]; + out_filename = argv[3]; + + /* + * set up the connection + */ + conn = PQsetdb(NULL, NULL, NULL, NULL, database); + + /* check to see that the backend connection was successfully made */ + if (PQstatus(conn) != CONNECTION_OK) + { + fprintf(stderr, "Connection to database failed: %s", + PQerrorMessage(conn)); + exit_nicely(conn); + } + + res = PQexec(conn, "begin"); + PQclear(res); + printf("importing file \"%s\" ...\n", in_filename); +/* lobjOid = importFile(conn, in_filename); */ + lobjOid = lo_import(conn, in_filename); + if (lobjOid == 0) + fprintf(stderr, "%s\n", PQerrorMessage(conn)); + else + { + printf("\tas large object %u.\n", lobjOid); + + printf("picking out bytes 4294967000-4294968000 of the large object\n"); + pickout(conn, lobjOid, 4294967000ULL, 1000); + + printf("overwriting bytes 4294967000-4294968000 of the large object with X's\n"); + overwrite(conn, lobjOid, 4294967000ULL, 1000); + + printf("exporting large object to file \"%s\" ...\n", out_filename); +/* exportFile(conn, lobjOid, out_filename); */ + if (!lo_export(conn, lobjOid, out_filename)) + fprintf(stderr, "%s\n", PQerrorMessage(conn)); + } + + res = PQexec(conn, "end"); + PQclear(res); + PQfinish(conn); + return 0; +}