Commit 26fe5648 authored by Tom Lane's avatar Tom Lane

Code review for 64-bit-large-object patch.

Fix broken-on-bigendian-machines byte-swapping functions, add missed update
of alternate regression expected file, improve error reporting, remove some
unnecessary code, sync testlo64.c with current testlo.c (it seems to have
been cloned from a very old copy of that), assorted cosmetic improvements.
parent 878daf2e
...@@ -39,7 +39,6 @@ ...@@ -39,7 +39,6 @@
#include "postgres.h" #include "postgres.h"
#include <fcntl.h> #include <fcntl.h>
#include <limits.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <unistd.h> #include <unistd.h>
...@@ -57,7 +56,9 @@ ...@@ -57,7 +56,9 @@
*/ */
bool lo_compat_privileges; bool lo_compat_privileges;
/*#define FSDB 1*/ /* define this to enable debug logging */
/* #define FSDB 1 */
/* chunk size for lo_import/lo_export transfers */
#define BUFSIZE 8192 #define BUFSIZE 8192
/* /*
...@@ -210,7 +211,6 @@ lo_write(int fd, const char *buf, int len) ...@@ -210,7 +211,6 @@ lo_write(int fd, const char *buf, int len)
return status; return status;
} }
Datum Datum
lo_lseek(PG_FUNCTION_ARGS) lo_lseek(PG_FUNCTION_ARGS)
{ {
...@@ -226,42 +226,31 @@ lo_lseek(PG_FUNCTION_ARGS) ...@@ -226,42 +226,31 @@ lo_lseek(PG_FUNCTION_ARGS)
status = inv_seek(cookies[fd], offset, whence); status = inv_seek(cookies[fd], offset, whence);
if (INT_MAX < status) /* guard against result overflow */
{ if (status != (int32) status)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_BLOB_OFFSET_OVERFLOW), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("offset overflow: %d", fd))); errmsg("lo_lseek result out of range for large-object descriptor %d",
PG_RETURN_INT32(-1); fd)));
}
PG_RETURN_INT32(status); PG_RETURN_INT32((int32) status);
} }
Datum Datum
lo_lseek64(PG_FUNCTION_ARGS) lo_lseek64(PG_FUNCTION_ARGS)
{ {
int32 fd = PG_GETARG_INT32(0); int32 fd = PG_GETARG_INT32(0);
int64 offset = PG_GETARG_INT64(1); int64 offset = PG_GETARG_INT64(1);
int32 whence = PG_GETARG_INT32(2); int32 whence = PG_GETARG_INT32(2);
MemoryContext currentContext; int64 status;
int64 status;
if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL) if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL)
{
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT), (errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("invalid large-object descriptor: %d", fd))); errmsg("invalid large-object descriptor: %d", fd)));
PG_RETURN_INT64(-1);
}
Assert(fscxt != NULL);
currentContext = MemoryContextSwitchTo(fscxt);
status = inv_seek(cookies[fd], offset, whence); status = inv_seek(cookies[fd], offset, whence);
MemoryContextSwitchTo(currentContext);
PG_RETURN_INT64(status); PG_RETURN_INT64(status);
} }
...@@ -301,7 +290,7 @@ Datum ...@@ -301,7 +290,7 @@ Datum
lo_tell(PG_FUNCTION_ARGS) lo_tell(PG_FUNCTION_ARGS)
{ {
int32 fd = PG_GETARG_INT32(0); int32 fd = PG_GETARG_INT32(0);
int64 offset = 0; int64 offset;
if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL) if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL)
ereport(ERROR, ereport(ERROR,
...@@ -310,37 +299,30 @@ lo_tell(PG_FUNCTION_ARGS) ...@@ -310,37 +299,30 @@ lo_tell(PG_FUNCTION_ARGS)
offset = inv_tell(cookies[fd]); offset = inv_tell(cookies[fd]);
if (INT_MAX < offset) /* guard against result overflow */
{ if (offset != (int32) offset)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_BLOB_OFFSET_OVERFLOW), (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("offset overflow: %d", fd))); errmsg("lo_tell result out of range for large-object descriptor %d",
PG_RETURN_INT32(-1); fd)));
}
PG_RETURN_INT32(offset); PG_RETURN_INT32((int32) offset);
} }
Datum Datum
lo_tell64(PG_FUNCTION_ARGS) lo_tell64(PG_FUNCTION_ARGS)
{ {
int32 fd = PG_GETARG_INT32(0); int32 fd = PG_GETARG_INT32(0);
int64 offset;
if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL) if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL)
{
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT), (errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("invalid large-object descriptor: %d", fd))); errmsg("invalid large-object descriptor: %d", fd)));
PG_RETURN_INT64(-1);
}
/* offset = inv_tell(cookies[fd]);
* 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 PG_RETURN_INT64(offset);
* assume...
*/
PG_RETURN_INT64(inv_tell(cookies[fd]));
} }
Datum Datum
......
...@@ -30,6 +30,8 @@ ...@@ -30,6 +30,8 @@
*/ */
#include "postgres.h" #include "postgres.h"
#include <limits.h>
#include "access/genam.h" #include "access/genam.h"
#include "access/heapam.h" #include "access/heapam.h"
#include "access/sysattr.h" #include "access/sysattr.h"
...@@ -264,7 +266,10 @@ inv_open(Oid lobjId, int flags, MemoryContext mcxt) ...@@ -264,7 +266,10 @@ inv_open(Oid lobjId, int flags, MemoryContext mcxt)
retval->flags = IFS_RDLOCK; retval->flags = IFS_RDLOCK;
} }
else else
elog(ERROR, "invalid flags: %d", flags); ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("invalid flags for opening a large object: %d",
flags)));
/* Can't use LargeObjectExists here because it always uses SnapshotNow */ /* Can't use LargeObjectExists here because it always uses SnapshotNow */
if (!myLargeObjectExists(lobjId, retval->snapshot)) if (!myLargeObjectExists(lobjId, retval->snapshot))
...@@ -381,34 +386,45 @@ inv_getsize(LargeObjectDesc *obj_desc) ...@@ -381,34 +386,45 @@ inv_getsize(LargeObjectDesc *obj_desc)
int64 int64
inv_seek(LargeObjectDesc *obj_desc, int64 offset, int whence) inv_seek(LargeObjectDesc *obj_desc, int64 offset, int whence)
{ {
int64 newoffset;
Assert(PointerIsValid(obj_desc)); Assert(PointerIsValid(obj_desc));
/*
* Note: overflow in the additions is possible, but since we will reject
* negative results, we don't need any extra test for that.
*/
switch (whence) switch (whence)
{ {
case SEEK_SET: case SEEK_SET:
if (offset < 0 || offset >= MAX_LARGE_OBJECT_SIZE) newoffset = offset;
elog(ERROR, "invalid seek offset: " INT64_FORMAT, offset);
obj_desc->offset = offset;
break; break;
case SEEK_CUR: case SEEK_CUR:
if ((offset + obj_desc->offset) < 0 || newoffset = obj_desc->offset + offset;
(offset + obj_desc->offset) >= MAX_LARGE_OBJECT_SIZE)
elog(ERROR, "invalid seek offset: " INT64_FORMAT, offset);
obj_desc->offset += offset;
break; break;
case SEEK_END: case SEEK_END:
{ newoffset = inv_getsize(obj_desc) + offset;
int64 pos = inv_getsize(obj_desc) + offset;
if (pos < 0 || pos >= MAX_LARGE_OBJECT_SIZE)
elog(ERROR, "invalid seek offset: " INT64_FORMAT, offset);
obj_desc->offset = pos;
}
break; break;
default: default:
elog(ERROR, "invalid whence: %d", whence); ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("invalid whence setting: %d", whence)));
newoffset = 0; /* keep compiler quiet */
break;
} }
return obj_desc->offset;
/*
* use errmsg_internal here because we don't want to expose INT64_FORMAT
* in translatable strings; doing better is not worth the trouble
*/
if (newoffset < 0 || newoffset > MAX_LARGE_OBJECT_SIZE)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg_internal("invalid large object seek target: " INT64_FORMAT,
newoffset)));
obj_desc->offset = newoffset;
return newoffset;
} }
int64 int64
...@@ -438,9 +454,6 @@ inv_read(LargeObjectDesc *obj_desc, char *buf, int nbytes) ...@@ -438,9 +454,6 @@ inv_read(LargeObjectDesc *obj_desc, char *buf, int nbytes)
if (nbytes <= 0) if (nbytes <= 0)
return 0; return 0;
if ((nbytes + obj_desc->offset) > MAX_LARGE_OBJECT_SIZE)
elog(ERROR, "invalid read request size: %d", nbytes);
open_lo_relation(); open_lo_relation();
ScanKeyInit(&skey[0], ScanKeyInit(&skey[0],
...@@ -559,13 +572,18 @@ inv_write(LargeObjectDesc *obj_desc, const char *buf, int nbytes) ...@@ -559,13 +572,18 @@ inv_write(LargeObjectDesc *obj_desc, const char *buf, int nbytes)
if (!LargeObjectExists(obj_desc->id)) if (!LargeObjectExists(obj_desc->id))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT), (errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("large object %u was already dropped", obj_desc->id))); errmsg("large object %u was already dropped",
obj_desc->id)));
if (nbytes <= 0) if (nbytes <= 0)
return 0; return 0;
/* this addition can't overflow because nbytes is only int32 */
if ((nbytes + obj_desc->offset) > MAX_LARGE_OBJECT_SIZE) if ((nbytes + obj_desc->offset) > MAX_LARGE_OBJECT_SIZE)
elog(ERROR, "invalid write request size: %d", nbytes); ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("invalid large object write request size: %d",
nbytes)));
open_lo_relation(); open_lo_relation();
...@@ -759,7 +777,18 @@ inv_truncate(LargeObjectDesc *obj_desc, int64 len) ...@@ -759,7 +777,18 @@ inv_truncate(LargeObjectDesc *obj_desc, int64 len)
if (!LargeObjectExists(obj_desc->id)) if (!LargeObjectExists(obj_desc->id))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT), (errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("large object %u was already dropped", obj_desc->id))); errmsg("large object %u was already dropped",
obj_desc->id)));
/*
* use errmsg_internal here because we don't want to expose INT64_FORMAT
* in translatable strings; doing better is not worth the trouble
*/
if (len < 0 || len > MAX_LARGE_OBJECT_SIZE)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg_internal("invalid large object truncation target: " INT64_FORMAT,
len)));
open_lo_relation(); open_lo_relation();
......
...@@ -199,7 +199,6 @@ Section: Class 22 - Data Exception ...@@ -199,7 +199,6 @@ Section: Class 22 - Data Exception
2200N E ERRCODE_INVALID_XML_CONTENT invalid_xml_content 2200N E ERRCODE_INVALID_XML_CONTENT invalid_xml_content
2200S E ERRCODE_INVALID_XML_COMMENT invalid_xml_comment 2200S E ERRCODE_INVALID_XML_COMMENT invalid_xml_comment
2200T E ERRCODE_INVALID_XML_PROCESSING_INSTRUCTION invalid_xml_processing_instruction 2200T E ERRCODE_INVALID_XML_PROCESSING_INSTRUCTION invalid_xml_processing_instruction
22P07 E ERRCODE_BLOB_OFFSET_OVERFLOW blob_offset_overflow
Section: Class 23 - Integrity Constraint Violation Section: Class 23 - Integrity Constraint Violation
......
...@@ -1040,7 +1040,7 @@ DATA(insert OID = 955 ( lowrite PGNSP PGUID 12 1 0 0 0 f f f f t f v 2 0 23 ...@@ -1040,7 +1040,7 @@ DATA(insert OID = 955 ( lowrite PGNSP PGUID 12 1 0 0 0 f f f f t f v 2 0 23
DESCR("large object write"); DESCR("large object write");
DATA(insert OID = 956 ( lo_lseek PGNSP PGUID 12 1 0 0 0 f f f f t f v 3 0 23 "23 23 23" _null_ _null_ _null_ _null_ lo_lseek _null_ _null_ _null_ )); DATA(insert OID = 956 ( lo_lseek PGNSP PGUID 12 1 0 0 0 f f f f t f v 3 0 23 "23 23 23" _null_ _null_ _null_ _null_ lo_lseek _null_ _null_ _null_ ));
DESCR("large object seek"); DESCR("large object seek");
DATA(insert OID = 3170 ( lo_lseek64 PGNSP PGUID 12 1 0 0 0 f f f f t f v 3 0 20 "23 20 23" _null_ _null_ _null_ _null_ lo_lseek64 _null_ _null_ _null_ )); DATA(insert OID = 3170 ( lo_lseek64 PGNSP PGUID 12 1 0 0 0 f f f f t f v 3 0 20 "23 20 23" _null_ _null_ _null_ _null_ lo_lseek64 _null_ _null_ _null_ ));
DESCR("large object seek (64 bit)"); DESCR("large object seek (64 bit)");
DATA(insert OID = 957 ( lo_creat PGNSP PGUID 12 1 0 0 0 f f f f t f v 1 0 26 "23" _null_ _null_ _null_ _null_ lo_creat _null_ _null_ _null_ )); DATA(insert OID = 957 ( lo_creat PGNSP PGUID 12 1 0 0 0 f f f f t f v 1 0 26 "23" _null_ _null_ _null_ _null_ lo_creat _null_ _null_ _null_ ));
DESCR("large object create"); DESCR("large object create");
......
...@@ -32,21 +32,19 @@ ...@@ -32,21 +32,19 @@
#include <fcntl.h> #include <fcntl.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <netinet/in.h> /* for ntohl/htonl */
#include <arpa/inet.h>
#include "libpq-fe.h" #include "libpq-fe.h"
#include "libpq-int.h" #include "libpq-int.h"
#include "libpq/libpq-fs.h" /* must come after sys/stat.h */ #include "libpq/libpq-fs.h" /* must come after sys/stat.h */
/* for ntohl/htonl */
#include <netinet/in.h>
#include <arpa/inet.h>
#define LO_BUFSIZE 8192 #define LO_BUFSIZE 8192
static int lo_initialize(PGconn *conn); static int lo_initialize(PGconn *conn);
static Oid lo_import_internal(PGconn *conn, const char *filename, Oid oid); static Oid lo_import_internal(PGconn *conn, const char *filename, Oid oid);
static pg_int64 lo_hton64(pg_int64 host64); static pg_int64 lo_hton64(pg_int64 host64);
static pg_int64 lo_ntoh64(pg_int64 net64); static pg_int64 lo_ntoh64(pg_int64 net64);
/* /*
* lo_open * lo_open
...@@ -373,7 +371,7 @@ lo_lseek64(PGconn *conn, int fd, pg_int64 offset, int whence) ...@@ -373,7 +371,7 @@ lo_lseek64(PGconn *conn, int fd, pg_int64 offset, int whence)
{ {
PQArgBlock argv[3]; PQArgBlock argv[3];
PGresult *res; PGresult *res;
pg_int64 retval; pg_int64 retval;
int result_len; int result_len;
if (conn == NULL || conn->lobjfuncs == NULL) if (conn == NULL || conn->lobjfuncs == NULL)
...@@ -403,11 +401,11 @@ lo_lseek64(PGconn *conn, int fd, pg_int64 offset, int whence) ...@@ -403,11 +401,11 @@ lo_lseek64(PGconn *conn, int fd, pg_int64 offset, int whence)
argv[2].u.integer = whence; argv[2].u.integer = whence;
res = PQfn(conn, conn->lobjfuncs->fn_lo_lseek64, res = PQfn(conn, conn->lobjfuncs->fn_lo_lseek64,
(int *)&retval, &result_len, 0, argv, 3); (int *) &retval, &result_len, 0, argv, 3);
if (PQresultStatus(res) == PGRES_COMMAND_OK) if (PQresultStatus(res) == PGRES_COMMAND_OK)
{ {
PQclear(res); PQclear(res);
return lo_ntoh64((pg_int64)retval); return lo_ntoh64(retval);
} }
else else
{ {
...@@ -506,9 +504,7 @@ lo_create(PGconn *conn, Oid lobjId) ...@@ -506,9 +504,7 @@ lo_create(PGconn *conn, Oid lobjId)
/* /*
* lo_tell * lo_tell
* returns the current seek location of the large object * returns the current seek location of the large object
*
*/ */
int int
lo_tell(PGconn *conn, int fd) lo_tell(PGconn *conn, int fd)
{ {
...@@ -575,7 +571,7 @@ lo_tell64(PGconn *conn, int fd) ...@@ -575,7 +571,7 @@ lo_tell64(PGconn *conn, int fd)
if (PQresultStatus(res) == PGRES_COMMAND_OK) if (PQresultStatus(res) == PGRES_COMMAND_OK)
{ {
PQclear(res); PQclear(res);
return lo_ntoh64((pg_int64) retval); return lo_ntoh64(retval);
} }
else else
{ {
...@@ -935,7 +931,9 @@ lo_initialize(PGconn *conn) ...@@ -935,7 +931,9 @@ lo_initialize(PGconn *conn)
PQclear(res); PQclear(res);
/* /*
* Finally check that we really got all large object interface functions * Finally check that we got all required large object interface functions
* (ones that have been added later than the stone age are instead checked
* only if used)
*/ */
if (lobjfuncs->fn_lo_open == 0) if (lobjfuncs->fn_lo_open == 0)
{ {
...@@ -993,30 +991,6 @@ lo_initialize(PGconn *conn) ...@@ -993,30 +991,6 @@ lo_initialize(PGconn *conn)
free(lobjfuncs); free(lobjfuncs);
return -1; return -1;
} }
if (conn->sversion >= 90300)
{
if (lobjfuncs->fn_lo_lseek64 == 0)
{
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("cannot determine OID of function lo_lseek64\n"));
free(lobjfuncs);
return -1;
}
if (lobjfuncs->fn_lo_tell64 == 0)
{
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("cannot determine OID of function lo_tell64\n"));
free(lobjfuncs);
return -1;
}
if (lobjfuncs->fn_lo_truncate64 == 0)
{
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("cannot determine OID of function lo_truncate64\n"));
free(lobjfuncs);
return -1;
}
}
/* /*
* Put the structure into the connection control * Put the structure into the connection control
...@@ -1027,43 +1001,48 @@ lo_initialize(PGconn *conn) ...@@ -1027,43 +1001,48 @@ lo_initialize(PGconn *conn)
/* /*
* lo_hton64 * lo_hton64
* converts an 64-bit integer from host byte order to network byte order * converts a 64-bit integer from host byte order to network byte order
*/ */
static pg_int64 static pg_int64
lo_hton64(pg_int64 host64) lo_hton64(pg_int64 host64)
{ {
pg_int64 result; union
uint32 h32, l32; {
pg_int64 i64;
uint32 i32[2];
} swap;
uint32 t;
/* High order half first, since we're doing MSB-first */ /* High order half first, since we're doing MSB-first */
h32 = (uint32) (host64 >> 32); t = (uint32) (host64 >> 32);
swap.i32[0] = htonl(t);
/* Now the low order half */ /* Now the low order half */
l32 = (uint32) (host64 & 0xffffffff); t = (uint32) host64;
swap.i32[1] = htonl(t);
result = htonl(l32);
result <<= 32;
result |= htonl(h32);
return result; return swap.i64;
} }
/* /*
* lo_ntoh64 * lo_ntoh64
* converts an 64-bit integer from network byte order to host byte order * converts a 64-bit integer from network byte order to host byte order
*/ */
static pg_int64 static pg_int64
lo_ntoh64(pg_int64 net64) lo_ntoh64(pg_int64 net64)
{ {
pg_int64 result; union
uint32 h32, l32; {
pg_int64 i64;
uint32 i32[2];
} swap;
pg_int64 result;
l32 = (uint32) (net64 >> 32); swap.i64 = net64;
h32 = (uint32) (net64 & 0xffffffff);
result = ntohl(h32); result = (uint32) ntohl(swap.i32[0]);
result <<= 32; result <<= 32;
result |= ntohl(l32); result |= (uint32) ntohl(swap.i32[1]);
return result; return result;
} }
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* testlo64.c * testlo64.c
* test using large objects with libpq using 64-bit APIs * test using large objects with libpq using 64-bit APIs
* *
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* *
...@@ -46,7 +46,7 @@ importFile(PGconn *conn, char *filename) ...@@ -46,7 +46,7 @@ importFile(PGconn *conn, char *filename)
fd = open(filename, O_RDONLY, 0666); fd = open(filename, O_RDONLY, 0666);
if (fd < 0) if (fd < 0)
{ /* error */ { /* error */
fprintf(stderr, "can't open unix file\"%s\"\n", filename); fprintf(stderr, "cannot open unix file\"%s\"\n", filename);
} }
/* /*
...@@ -54,7 +54,7 @@ importFile(PGconn *conn, char *filename) ...@@ -54,7 +54,7 @@ importFile(PGconn *conn, char *filename)
*/ */
lobjId = lo_creat(conn, INV_READ | INV_WRITE); lobjId = lo_creat(conn, INV_READ | INV_WRITE);
if (lobjId == 0) if (lobjId == 0)
fprintf(stderr, "can't create large object"); fprintf(stderr, "cannot create large object");
lobj_fd = lo_open(conn, lobjId, INV_WRITE); lobj_fd = lo_open(conn, lobjId, INV_WRITE);
...@@ -81,24 +81,16 @@ pickout(PGconn *conn, Oid lobjId, pg_int64 start, int len) ...@@ -81,24 +81,16 @@ pickout(PGconn *conn, Oid lobjId, pg_int64 start, int len)
char *buf; char *buf;
int nbytes; int nbytes;
int nread; int nread;
pg_int64 pos;
lobj_fd = lo_open(conn, lobjId, INV_READ); lobj_fd = lo_open(conn, lobjId, INV_READ);
if (lobj_fd < 0) if (lobj_fd < 0)
fprintf(stderr, "can't open large object %u", lobjId); fprintf(stderr, "cannot open large object %u", lobjId);
if (lo_tell64(conn, lobj_fd) < 0) if (lo_lseek64(conn, lobj_fd, start, SEEK_SET) < 0)
{ fprintf(stderr, "error in lo_lseek64: %s", PQerrorMessage(conn));
fprintf(stderr, "error lo_tell64: %s\n", PQerrorMessage(conn));
}
if ((pos=lo_lseek64(conn, lobj_fd, start, SEEK_SET)) < 0)
{
fprintf(stderr, "error lo_lseek64: %s\n", PQerrorMessage(conn));
return;
}
fprintf(stderr, "before read: retval of lo_lseek64 : %lld\n", (long long int) pos); if (lo_tell64(conn, lobj_fd) != start)
fprintf(stderr, "error in lo_tell64: %s", PQerrorMessage(conn));
buf = malloc(len + 1); buf = malloc(len + 1);
...@@ -114,10 +106,6 @@ pickout(PGconn *conn, Oid lobjId, pg_int64 start, int len) ...@@ -114,10 +106,6 @@ pickout(PGconn *conn, Oid lobjId, pg_int64 start, int len)
} }
free(buf); free(buf);
fprintf(stderr, "\n"); fprintf(stderr, "\n");
pos = lo_tell64(conn, lobj_fd);
fprintf(stderr, "after read: retval of lo_tell64 : %lld\n\n", (long long int) pos);
lo_close(conn, lobj_fd); lo_close(conn, lobj_fd);
} }
...@@ -129,18 +117,13 @@ overwrite(PGconn *conn, Oid lobjId, pg_int64 start, int len) ...@@ -129,18 +117,13 @@ overwrite(PGconn *conn, Oid lobjId, pg_int64 start, int len)
int nbytes; int nbytes;
int nwritten; int nwritten;
int i; int i;
pg_int64 pos;
lobj_fd = lo_open(conn, lobjId, INV_READ | INV_WRITE); lobj_fd = lo_open(conn, lobjId, INV_WRITE);
if (lobj_fd < 0) if (lobj_fd < 0)
fprintf(stderr, "can't open large object %u", lobjId); fprintf(stderr, "cannot open large object %u", lobjId);
if ((pos=lo_lseek64(conn, lobj_fd, start, SEEK_SET)) < 0) if (lo_lseek64(conn, lobj_fd, start, SEEK_SET) < 0)
{ fprintf(stderr, "error in lo_lseek64: %s", PQerrorMessage(conn));
fprintf(stderr, "error lo_lseek64: %s\n", PQerrorMessage(conn));
return;
}
fprintf(stderr, "before write: retval of lo_lseek64 : %lld\n", (long long int) pos);
buf = malloc(len + 1); buf = malloc(len + 1);
...@@ -160,30 +143,22 @@ overwrite(PGconn *conn, Oid lobjId, pg_int64 start, int len) ...@@ -160,30 +143,22 @@ overwrite(PGconn *conn, Oid lobjId, pg_int64 start, int len)
} }
} }
free(buf); free(buf);
fprintf(stderr, "\n");
pos = lo_tell64(conn, lobj_fd);
fprintf(stderr, "after write: retval of lo_tell64 : %lld\n\n", (long long int) pos);
lo_close(conn, lobj_fd); lo_close(conn, lobj_fd);
} }
static void static void
my_truncate(PGconn *conn, Oid lobjId, size_t len) my_truncate(PGconn *conn, Oid lobjId, pg_int64 len)
{ {
int lobj_fd; int lobj_fd;
lobj_fd = lo_open(conn, lobjId, INV_READ | INV_WRITE); lobj_fd = lo_open(conn, lobjId, INV_READ | INV_WRITE);
if (lobj_fd < 0) if (lobj_fd < 0)
fprintf(stderr, "can't open large object %u", lobjId); fprintf(stderr, "cannot open large object %u", lobjId);
if (lo_truncate64(conn, lobj_fd, len) < 0) if (lo_truncate64(conn, lobj_fd, len) < 0)
{ fprintf(stderr, "error in lo_truncate64: %s", PQerrorMessage(conn));
fprintf(stderr, "error lo_truncate64: %s\n", PQerrorMessage(conn));
return;
}
fprintf(stderr, "\n");
lo_close(conn, lobj_fd); lo_close(conn, lobj_fd);
} }
...@@ -203,11 +178,11 @@ exportFile(PGconn *conn, Oid lobjId, char *filename) ...@@ -203,11 +178,11 @@ exportFile(PGconn *conn, Oid lobjId, char *filename)
int fd; int fd;
/* /*
* create an inversion "object" * open the large object
*/ */
lobj_fd = lo_open(conn, lobjId, INV_READ); lobj_fd = lo_open(conn, lobjId, INV_READ);
if (lobj_fd < 0) if (lobj_fd < 0)
fprintf(stderr, "can't open large object %u", lobjId); fprintf(stderr, "cannot open large object %u", lobjId);
/* /*
* open the file to be written to * open the file to be written to
...@@ -215,12 +190,12 @@ exportFile(PGconn *conn, Oid lobjId, char *filename) ...@@ -215,12 +190,12 @@ exportFile(PGconn *conn, Oid lobjId, char *filename)
fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666); fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666);
if (fd < 0) if (fd < 0)
{ /* error */ { /* error */
fprintf(stderr, "can't open unix file\"%s\"", fprintf(stderr, "cannot open unix file\"%s\"",
filename); filename);
} }
/* /*
* read in from the Unix file and write to the inversion file * read in from the inversion file and write to the Unix file
*/ */
while ((nbytes = lo_read(conn, lobj_fd, buf, BUFSIZE)) > 0) while ((nbytes = lo_read(conn, lobj_fd, buf, BUFSIZE)) > 0)
{ {
...@@ -293,24 +268,22 @@ main(int argc, char **argv) ...@@ -293,24 +268,22 @@ main(int argc, char **argv)
printf("\tas large object %u.\n", lobjOid); printf("\tas large object %u.\n", lobjOid);
printf("picking out bytes 4294967000-4294968000 of the large object\n"); printf("picking out bytes 4294967000-4294968000 of the large object\n");
pickout(conn, lobjOid, 4294967000ULL, 1000); pickout(conn, lobjOid, 4294967000U, 1000);
printf("overwriting bytes 4294967000-4294968000 of the large object with X's\n"); printf("overwriting bytes 4294967000-4294968000 of the large object with X's\n");
overwrite(conn, lobjOid, 4294967000ULL, 1000); overwrite(conn, lobjOid, 4294967000U, 1000);
printf("exporting large object to file \"%s\" ...\n", out_filename); printf("exporting large object to file \"%s\" ...\n", out_filename);
/* exportFile(conn, lobjOid, out_filename); */ /* exportFile(conn, lobjOid, out_filename); */
if (!lo_export(conn, lobjOid, out_filename)) if (!lo_export(conn, lobjOid, out_filename))
fprintf(stderr, "%s\n", PQerrorMessage(conn)); fprintf(stderr, "%s\n", PQerrorMessage(conn));
printf("truncating to 3294968000 byte\n"); printf("truncating to 3294968000 bytes\n");
my_truncate(conn, lobjOid, 3294968000ULL); my_truncate(conn, lobjOid, 3294968000U);
printf("exporting truncated large object to file \"%s\" ...\n", out_filename2); printf("exporting truncated large object to file \"%s\" ...\n", out_filename2);
if (!lo_export(conn, lobjOid, out_filename2)) if (!lo_export(conn, lobjOid, out_filename2))
fprintf(stderr, "%s\n", PQerrorMessage(conn)); fprintf(stderr, "%s\n", PQerrorMessage(conn));
} }
res = PQexec(conn, "end"); res = PQexec(conn, "end");
......
...@@ -125,7 +125,7 @@ SELECT lo_tell(fd) FROM lotest_stash_values; ...@@ -125,7 +125,7 @@ SELECT lo_tell(fd) FROM lotest_stash_values;
SELECT lo_close(fd) FROM lotest_stash_values; SELECT lo_close(fd) FROM lotest_stash_values;
END; END;
-- Test 64-bit largelbject functions. -- Test 64-bit large object functions.
BEGIN; BEGIN;
UPDATE lotest_stash_values SET fd = lo_open(loid, CAST(x'20000' | x'40000' AS integer)); UPDATE lotest_stash_values SET fd = lo_open(loid, CAST(x'20000' | x'40000' AS integer));
......
...@@ -210,7 +210,7 @@ SELECT lo_close(fd) FROM lotest_stash_values; ...@@ -210,7 +210,7 @@ SELECT lo_close(fd) FROM lotest_stash_values;
(1 row) (1 row)
END; END;
-- Test 64-bit largelbject functions. -- Test 64-bit large object functions.
BEGIN; BEGIN;
UPDATE lotest_stash_values SET fd = lo_open(loid, CAST(x'20000' | x'40000' AS integer)); UPDATE lotest_stash_values SET fd = lo_open(loid, CAST(x'20000' | x'40000' AS integer));
SELECT lo_lseek64(fd, 4294967296, 0) FROM lotest_stash_values; SELECT lo_lseek64(fd, 4294967296, 0) FROM lotest_stash_values;
......
...@@ -209,6 +209,88 @@ SELECT lo_close(fd) FROM lotest_stash_values; ...@@ -209,6 +209,88 @@ SELECT lo_close(fd) FROM lotest_stash_values;
0 0
(1 row) (1 row)
END;
-- Test 64-bit large object functions.
BEGIN;
UPDATE lotest_stash_values SET fd = lo_open(loid, CAST(x'20000' | x'40000' AS integer));
SELECT lo_lseek64(fd, 4294967296, 0) FROM lotest_stash_values;
lo_lseek64
------------
4294967296
(1 row)
SELECT lowrite(fd, 'offset:4GB') FROM lotest_stash_values;
lowrite
---------
10
(1 row)
SELECT lo_tell64(fd) FROM lotest_stash_values;
lo_tell64
------------
4294967306
(1 row)
SELECT lo_lseek64(fd, -10, 1) FROM lotest_stash_values;
lo_lseek64
------------
4294967296
(1 row)
SELECT lo_tell64(fd) FROM lotest_stash_values;
lo_tell64
------------
4294967296
(1 row)
SELECT loread(fd, 10) FROM lotest_stash_values;
loread
------------
offset:4GB
(1 row)
SELECT lo_truncate64(fd, 5000000000) FROM lotest_stash_values;
lo_truncate64
---------------
0
(1 row)
SELECT lo_lseek64(fd, 0, 2) FROM lotest_stash_values;
lo_lseek64
------------
5000000000
(1 row)
SELECT lo_tell64(fd) FROM lotest_stash_values;
lo_tell64
------------
5000000000
(1 row)
SELECT lo_truncate64(fd, 3000000000) FROM lotest_stash_values;
lo_truncate64
---------------
0
(1 row)
SELECT lo_lseek64(fd, 0, 2) FROM lotest_stash_values;
lo_lseek64
------------
3000000000
(1 row)
SELECT lo_tell64(fd) FROM lotest_stash_values;
lo_tell64
------------
3000000000
(1 row)
SELECT lo_close(fd) FROM lotest_stash_values;
lo_close
----------
0
(1 row)
END; END;
-- lo_unlink(lobjId oid) returns integer -- lo_unlink(lobjId oid) returns integer
-- return value appears to always be 1 -- return value appears to always be 1
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment