mirror of
https://github.com/postgres/postgres.git
synced 2025-07-31 22:04:40 +03:00
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.
This commit is contained in:
@ -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 @@
|
|||||||
*/
|
*/
|
||||||
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)
|
|||||||
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)
|
|||||||
|
|
||||||
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
|
|||||||
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)
|
|||||||
|
|
||||||
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 @@
|
|||||||
*/
|
*/
|
||||||
#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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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
|
|||||||
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
|
|||||||
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 @@
|
|||||||
|
|
||||||
#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)
|
|||||||
{
|
{
|
||||||
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)
|
|||||||
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)
|
|||||||
/*
|
/*
|
||||||
* 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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* 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);
|
return swap.i64;
|
||||||
result <<= 32;
|
|
||||||
result |= htonl(h32);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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 @@
|
|||||||
* 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)
|
|||||||
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)
|
|||||||
*/
|
*/
|
||||||
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)
|
|||||||
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)
|
if (lo_tell64(conn, lobj_fd) != start)
|
||||||
{
|
fprintf(stderr, "error in lo_tell64: %s", PQerrorMessage(conn));
|
||||||
fprintf(stderr, "error lo_lseek64: %s\n", PQerrorMessage(conn));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(stderr, "before read: retval of lo_lseek64 : %lld\n", (long long int) pos);
|
|
||||||
|
|
||||||
buf = malloc(len + 1);
|
buf = malloc(len + 1);
|
||||||
|
|
||||||
@ -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)
|
|||||||
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)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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;
|
|||||||
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;
|
|||||||
(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;
|
|||||||
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
|
||||||
|
Reference in New Issue
Block a user