diff --git a/src/backend/libpq/be-fsstubs.c b/src/backend/libpq/be-fsstubs.c index 7eff84e5d3322af2feff7969c6dc144b6aeffe08..a379bd05e8d9617e785c8147e5ad0e73921dd599 100644 --- a/src/backend/libpq/be-fsstubs.c +++ b/src/backend/libpq/be-fsstubs.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/libpq/be-fsstubs.c,v 1.55 2000/10/24 01:38:26 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/libpq/be-fsstubs.c,v 1.56 2000/10/24 03:14:08 tgl Exp $ * * NOTES * This should be moved to a more appropriate place. It is here @@ -49,15 +49,18 @@ /* [PA] is Pascal André <andre@via.ecp.fr> */ /*#define FSDB 1*/ -#define MAX_LOBJ_FDS 256 #define BUFSIZE 8192 /* - * LO "FD"s are indexes into this array. + * LO "FD"s are indexes into the cookies array. + * * A non-null entry is a pointer to a LargeObjectDesc allocated in the - * LO private memory context. + * LO private memory context. The cookies array itself is also dynamically + * allocated in that context. Its current allocated size is cookies_len + * entries, of which any unused entries will be NULL. */ -static LargeObjectDesc *cookies[MAX_LOBJ_FDS]; +static LargeObjectDesc **cookies = NULL; +static int cookies_size = 0; static MemoryContext fscxt = NULL; @@ -104,14 +107,8 @@ lo_open(PG_FUNCTION_ARGS) fd = newLOfd(lobjDesc); - /* switch context back to orig. */ MemoryContextSwitchTo(currentContext); -#if FSDB - if (fd < 0) /* newLOfd couldn't find a slot */ - elog(NOTICE, "Out of space for large object FDs"); -#endif - PG_RETURN_INT32(fd); } @@ -121,15 +118,10 @@ lo_close(PG_FUNCTION_ARGS) int32 fd = PG_GETARG_INT32(0); MemoryContext currentContext; - if (fd < 0 || fd >= MAX_LOBJ_FDS) - { - elog(ERROR, "lo_close: large obj descriptor (%d) out of range", fd); - PG_RETURN_INT32(-2); - } - if (cookies[fd] == NULL) + if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL) { elog(ERROR, "lo_close: invalid large obj descriptor (%d)", fd); - PG_RETURN_INT32(-3); + PG_RETURN_INT32(-1); } #if FSDB elog(NOTICE, "lo_close(%d)", fd); @@ -162,15 +154,10 @@ lo_read(int fd, char *buf, int len) MemoryContext currentContext; int status; - if (fd < 0 || fd >= MAX_LOBJ_FDS) - { - elog(ERROR, "lo_read: large obj descriptor (%d) out of range", fd); - return -2; - } - if (cookies[fd] == NULL) + if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL) { elog(ERROR, "lo_read: invalid large obj descriptor (%d)", fd); - return -3; + return -1; } Assert(fscxt != NULL); @@ -189,15 +176,10 @@ lo_write(int fd, char *buf, int len) MemoryContext currentContext; int status; - if (fd < 0 || fd >= MAX_LOBJ_FDS) - { - elog(ERROR, "lo_write: large obj descriptor (%d) out of range", fd); - return -2; - } - if (cookies[fd] == NULL) + if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL) { elog(ERROR, "lo_write: invalid large obj descriptor (%d)", fd); - return -3; + return -1; } Assert(fscxt != NULL); @@ -220,15 +202,10 @@ lo_lseek(PG_FUNCTION_ARGS) MemoryContext currentContext; int status; - if (fd < 0 || fd >= MAX_LOBJ_FDS) - { - elog(ERROR, "lo_lseek: large obj descriptor (%d) out of range", fd); - PG_RETURN_INT32(-2); - } - if (cookies[fd] == NULL) + if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL) { elog(ERROR, "lo_lseek: invalid large obj descriptor (%d)", fd); - PG_RETURN_INT32(-3); + PG_RETURN_INT32(-1); } Assert(fscxt != NULL); @@ -280,15 +257,10 @@ lo_tell(PG_FUNCTION_ARGS) { int32 fd = PG_GETARG_INT32(0); - if (fd < 0 || fd >= MAX_LOBJ_FDS) - { - elog(ERROR, "lo_tell: large object descriptor (%d) out of range", fd); - PG_RETURN_INT32(-2); - } - if (cookies[fd] == NULL) + if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL) { elog(ERROR, "lo_tell: invalid large object descriptor (%d)", fd); - PG_RETURN_INT32(-3); + PG_RETURN_INT32(-1); } /* @@ -304,13 +276,30 @@ lo_unlink(PG_FUNCTION_ARGS) { Oid lobjId = PG_GETARG_OID(0); + /* + * If there are any open LO FDs referencing that ID, close 'em. + */ + if (fscxt != NULL) + { + MemoryContext currentContext; + int i; + + currentContext = MemoryContextSwitchTo(fscxt); + for (i = 0; i < cookies_size; i++) + { + if (cookies[i] != NULL && cookies[i]->id == lobjId) + { + inv_close(cookies[i]); + deleteLOfd(i); + } + } + MemoryContextSwitchTo(currentContext); + } + /* * inv_drop does not need a context switch, indeed it doesn't touch * any LO-specific data structures at all. (Again, that's probably * more than this module ought to be assuming.) - * - * XXX there ought to be some code to clean up any open LO FDs that - * reference the specified LO... as is, they remain "open". */ PG_RETURN_INT32(inv_drop(lobjId)); } @@ -502,7 +491,7 @@ lo_commit(bool isCommit) * Clean out still-open index scans (not necessary if aborting) and * clear cookies array so that LO fds are no longer good. */ - for (i = 0; i < MAX_LOBJ_FDS; i++) + for (i = 0; i < cookies_size; i++) { if (cookies[i] != NULL) { @@ -512,6 +501,10 @@ lo_commit(bool isCommit) } } + /* Needn't actually pfree since we're about to zap context */ + cookies = NULL; + cookies_size = 0; + MemoryContextSwitchTo(currentContext); /* Release the LO memory context to prevent permanent memory leaks. */ @@ -527,18 +520,45 @@ lo_commit(bool isCommit) static int newLOfd(LargeObjectDesc *lobjCookie) { - int i; + int i, + newsize; - for (i = 0; i < MAX_LOBJ_FDS; i++) + /* Try to find a free slot */ + for (i = 0; i < cookies_size; i++) { - if (cookies[i] == NULL) { cookies[i] = lobjCookie; return i; } } - return -1; + + /* No free slot, so make the array bigger */ + if (cookies_size <= 0) + { + /* First time through, arbitrarily make 64-element array */ + i = 0; + newsize = 64; + cookies = (LargeObjectDesc **) + palloc(newsize * sizeof(LargeObjectDesc *)); + MemSet(cookies, 0, newsize * sizeof(LargeObjectDesc *)); + cookies_size = newsize; + } + else + { + /* Double size of array */ + i = cookies_size; + newsize = cookies_size * 2; + cookies = (LargeObjectDesc **) + repalloc(cookies, newsize * sizeof(LargeObjectDesc *)); + MemSet(cookies + cookies_size, 0, + (newsize - cookies_size) * sizeof(LargeObjectDesc *)); + cookies_size = newsize; + } + + Assert(cookies[i] == NULL); + cookies[i] = lobjCookie; + return i; } static void