summaryrefslogtreecommitdiff
path: root/src/backend/libpq/be-fsstubs.c
diff options
context:
space:
mode:
authorTatsuo Ishii <ishii@postgresql.org>2012-10-07 08:36:48 +0900
committerTatsuo Ishii <ishii@postgresql.org>2012-10-07 08:36:48 +0900
commit461ef73f0977c95c9452680495bc161618db9227 (patch)
treeef9883b9fbbb57875a7ec7023fce944f840afb71 /src/backend/libpq/be-fsstubs.c
parentae835c7d6e202e99796c58093ef781477e54c459 (diff)
Add API for 64-bit large object access. Now users can access up to
4TB large objects (standard 8KB BLCKSZ case). For this purpose new libpq API lo_lseek64, lo_tell64 and lo_truncate64 are added. Also corresponding new backend functions lo_lseek64, lo_tell64 and lo_truncate64 are added. inv_api.c is changed to handle 64-bit offsets. Patch contributed by Nozomi Anzai (backend side) and Yugo Nagata (frontend side, docs, regression tests and example program). Reviewed by Kohei Kaigai. Committed by Tatsuo Ishii with minor editings.
Diffstat (limited to 'src/backend/libpq/be-fsstubs.c')
-rw-r--r--src/backend/libpq/be-fsstubs.c101
1 files changed, 99 insertions, 2 deletions
diff --git a/src/backend/libpq/be-fsstubs.c b/src/backend/libpq/be-fsstubs.c
index 6f7e474f675..4bc81ba9f4d 100644
--- a/src/backend/libpq/be-fsstubs.c
+++ b/src/backend/libpq/be-fsstubs.c
@@ -39,6 +39,7 @@
#include "postgres.h"
#include <fcntl.h>
+#include <limits.h>
#include <sys/stat.h>
#include <unistd.h>
@@ -216,7 +217,7 @@ lo_lseek(PG_FUNCTION_ARGS)
int32 fd = PG_GETARG_INT32(0);
int32 offset = PG_GETARG_INT32(1);
int32 whence = PG_GETARG_INT32(2);
- int status;
+ int64 status;
if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL)
ereport(ERROR,
@@ -225,9 +226,45 @@ lo_lseek(PG_FUNCTION_ARGS)
status = inv_seek(cookies[fd], offset, whence);
+ if (INT_MAX < status)
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_BLOB_OFFSET_OVERFLOW),
+ errmsg("offset overflow: %d", fd)));
+ PG_RETURN_INT32(-1);
+ }
+
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_seek(cookies[fd], offset, whence);
+
+ MemoryContextSwitchTo(currentContext);
+
+ PG_RETURN_INT64(status);
+}
+
Datum
lo_creat(PG_FUNCTION_ARGS)
{
@@ -264,13 +301,46 @@ Datum
lo_tell(PG_FUNCTION_ARGS)
{
int32 fd = PG_GETARG_INT32(0);
+ int64 offset = 0;
+
+ if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("invalid large-object descriptor: %d", fd)));
+
+ offset = inv_tell(cookies[fd]);
+
+ if (INT_MAX < offset)
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_BLOB_OFFSET_OVERFLOW),
+ errmsg("offset overflow: %d", fd)));
+ PG_RETURN_INT32(-1);
+ }
+
+ PG_RETURN_INT32(offset);
+}
+
+
+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);
+ }
- PG_RETURN_INT32(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
+ * assume...
+ */
+ PG_RETURN_INT64(inv_tell(cookies[fd]));
}
Datum
@@ -533,6 +603,33 @@ lo_truncate(PG_FUNCTION_ARGS)
PG_RETURN_INT32(0);
}
+Datum
+lo_truncate64(PG_FUNCTION_ARGS)
+{
+ int32 fd = PG_GETARG_INT32(0);
+ int64 len = PG_GETARG_INT64(1);
+
+ if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("invalid large-object descriptor: %d", fd)));
+
+ /* Permission checks */
+ if (!lo_compat_privileges &&
+ pg_largeobject_aclcheck_snapshot(cookies[fd]->id,
+ GetUserId(),
+ ACL_UPDATE,
+ cookies[fd]->snapshot) != ACLCHECK_OK)
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("permission denied for large object %u",
+ cookies[fd]->id)));
+
+ inv_truncate(cookies[fd], len);
+
+ PG_RETURN_INT32(0);
+}
+
/*
* AtEOXact_LargeObject -
* prepares large objects for transaction commit