PostgreSQL Source Code git master
be-fsstubs.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * be-fsstubs.c
4 * Builtin functions for open/close/read/write operations on large objects
5 *
6 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
8 *
9 *
10 * IDENTIFICATION
11 * src/backend/libpq/be-fsstubs.c
12 *
13 * NOTES
14 * This should be moved to a more appropriate place. It is here
15 * for lack of a better place.
16 *
17 * These functions store LargeObjectDesc structs in a private MemoryContext,
18 * which means that large object descriptors hang around until we destroy
19 * the context at transaction end. It'd be possible to prolong the lifetime
20 * of the context so that LO FDs are good across transactions (for example,
21 * we could release the context only if we see that no FDs remain open).
22 * But we'd need additional state in order to do the right thing at the
23 * end of an aborted transaction. FDs opened during an aborted xact would
24 * still need to be closed, since they might not be pointing at valid
25 * relations at all. Locking semantics are also an interesting problem
26 * if LOs stay open across transactions. For now, we'll stick with the
27 * existing documented semantics of LO FDs: they're only good within a
28 * transaction.
29 *
30 * As of PostgreSQL 8.0, much of the angst expressed above is no longer
31 * relevant, and in fact it'd be pretty easy to allow LO FDs to stay
32 * open across transactions. (Snapshot relevancy would still be an issue.)
33 * However backwards compatibility suggests that we should stick to the
34 * status quo.
35 *
36 *-------------------------------------------------------------------------
37 */
38
39#include "postgres.h"
40
41#include <fcntl.h>
42#include <sys/stat.h>
43#include <unistd.h>
44
45#include "access/xact.h"
47#include "libpq/be-fsstubs.h"
48#include "libpq/libpq-fs.h"
49#include "miscadmin.h"
50#include "storage/fd.h"
52#include "utils/acl.h"
53#include "utils/builtins.h"
54#include "utils/memutils.h"
55#include "utils/snapmgr.h"
56#include "varatt.h"
57
58/* define this to enable debug logging */
59/* #define FSDB 1 */
60/* chunk size for lo_import/lo_export transfers */
61#define BUFSIZE 8192
62
63/*
64 * LO "FD"s are indexes into the cookies array.
65 *
66 * A non-null entry is a pointer to a LargeObjectDesc allocated in the
67 * LO private memory context "fscxt". The cookies array itself is also
68 * dynamically allocated in that context. Its current allocated size is
69 * cookies_size entries, of which any unused entries will be NULL.
70 */
71static LargeObjectDesc **cookies = NULL;
72static int cookies_size = 0;
73
74static bool lo_cleanup_needed = false;
75static MemoryContext fscxt = NULL;
76
77static int newLOfd(void);
78static void closeLOfd(int fd);
79static Oid lo_import_internal(text *filename, Oid lobjOid);
80
81
82/*****************************************************************************
83 * File Interfaces for Large Objects
84 *****************************************************************************/
85
88{
89 Oid lobjId = PG_GETARG_OID(0);
91 LargeObjectDesc *lobjDesc;
92 int fd;
93
94#ifdef FSDB
95 elog(DEBUG4, "lo_open(%u,%d)", lobjId, mode);
96#endif
97
98 if (mode & INV_WRITE)
99 PreventCommandIfReadOnly("lo_open(INV_WRITE)");
100
101 /*
102 * Allocate a large object descriptor first. This will also create
103 * 'fscxt' if this is the first LO opened in this transaction.
104 */
105 fd = newLOfd();
106
107 lobjDesc = inv_open(lobjId, mode, fscxt);
108 lobjDesc->subid = GetCurrentSubTransactionId();
109
110 /*
111 * We must register the snapshot in TopTransaction's resowner so that it
112 * stays alive until the LO is closed rather than until the current portal
113 * shuts down.
114 */
115 if (lobjDesc->snapshot)
116 lobjDesc->snapshot = RegisterSnapshotOnOwner(lobjDesc->snapshot,
118
119 Assert(cookies[fd] == NULL);
120 cookies[fd] = lobjDesc;
121
123}
124
125Datum
127{
129
130 if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL)
132 (errcode(ERRCODE_UNDEFINED_OBJECT),
133 errmsg("invalid large-object descriptor: %d", fd)));
134
135#ifdef FSDB
136 elog(DEBUG4, "lo_close(%d)", fd);
137#endif
138
139 closeLOfd(fd);
140
142}
143
144
145/*****************************************************************************
146 * Bare Read/Write operations --- these are not fmgr-callable!
147 *
148 * We assume the large object supports byte oriented reads and seeks so
149 * that our work is easier.
150 *
151 *****************************************************************************/
152
153int
154lo_read(int fd, char *buf, int len)
155{
156 int status;
157 LargeObjectDesc *lobj;
158
159 if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL)
161 (errcode(ERRCODE_UNDEFINED_OBJECT),
162 errmsg("invalid large-object descriptor: %d", fd)));
163 lobj = cookies[fd];
164
165 /*
166 * Check state. inv_read() would throw an error anyway, but we want the
167 * error to be about the FD's state not the underlying privilege; it might
168 * be that the privilege exists but user forgot to ask for read mode.
169 */
170 if ((lobj->flags & IFS_RDLOCK) == 0)
172 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
173 errmsg("large object descriptor %d was not opened for reading",
174 fd)));
175
176 status = inv_read(lobj, buf, len);
177
178 return status;
179}
180
181int
182lo_write(int fd, const char *buf, int len)
183{
184 int status;
185 LargeObjectDesc *lobj;
186
187 if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL)
189 (errcode(ERRCODE_UNDEFINED_OBJECT),
190 errmsg("invalid large-object descriptor: %d", fd)));
191 lobj = cookies[fd];
192
193 /* see comment in lo_read() */
194 if ((lobj->flags & IFS_WRLOCK) == 0)
196 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
197 errmsg("large object descriptor %d was not opened for writing",
198 fd)));
199
200 status = inv_write(lobj, buf, len);
201
202 return status;
203}
204
205Datum
207{
209 int32 offset = PG_GETARG_INT32(1);
210 int32 whence = PG_GETARG_INT32(2);
211 int64 status;
212
213 if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL)
215 (errcode(ERRCODE_UNDEFINED_OBJECT),
216 errmsg("invalid large-object descriptor: %d", fd)));
217
218 status = inv_seek(cookies[fd], offset, whence);
219
220 /* guard against result overflow */
221 if (status != (int32) status)
223 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
224 errmsg("lo_lseek result out of range for large-object descriptor %d",
225 fd)));
226
227 PG_RETURN_INT32((int32) status);
228}
229
230Datum
232{
234 int64 offset = PG_GETARG_INT64(1);
235 int32 whence = PG_GETARG_INT32(2);
236 int64 status;
237
238 if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL)
240 (errcode(ERRCODE_UNDEFINED_OBJECT),
241 errmsg("invalid large-object descriptor: %d", fd)));
242
243 status = inv_seek(cookies[fd], offset, whence);
244
245 PG_RETURN_INT64(status);
246}
247
248Datum
250{
251 Oid lobjId;
252
253 PreventCommandIfReadOnly("lo_creat()");
254
255 lo_cleanup_needed = true;
256 lobjId = inv_create(InvalidOid);
257
258 PG_RETURN_OID(lobjId);
259}
260
261Datum
263{
264 Oid lobjId = PG_GETARG_OID(0);
265
266 PreventCommandIfReadOnly("lo_create()");
267
268 lo_cleanup_needed = true;
269 lobjId = inv_create(lobjId);
270
271 PG_RETURN_OID(lobjId);
272}
273
274Datum
276{
278 int64 offset;
279
280 if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL)
282 (errcode(ERRCODE_UNDEFINED_OBJECT),
283 errmsg("invalid large-object descriptor: %d", fd)));
284
285 offset = inv_tell(cookies[fd]);
286
287 /* guard against result overflow */
288 if (offset != (int32) offset)
290 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
291 errmsg("lo_tell result out of range for large-object descriptor %d",
292 fd)));
293
294 PG_RETURN_INT32((int32) offset);
295}
296
297Datum
299{
301 int64 offset;
302
303 if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL)
305 (errcode(ERRCODE_UNDEFINED_OBJECT),
306 errmsg("invalid large-object descriptor: %d", fd)));
307
308 offset = inv_tell(cookies[fd]);
309
310 PG_RETURN_INT64(offset);
311}
312
313Datum
315{
316 Oid lobjId = PG_GETARG_OID(0);
317
318 PreventCommandIfReadOnly("lo_unlink()");
319
320 if (!LargeObjectExists(lobjId))
322 (errcode(ERRCODE_UNDEFINED_OBJECT),
323 errmsg("large object %u does not exist", lobjId)));
324
325 /*
326 * Must be owner of the large object. It would be cleaner to check this
327 * in inv_drop(), but we want to throw the error before not after closing
328 * relevant FDs.
329 */
331 !object_ownercheck(LargeObjectRelationId, lobjId, GetUserId()))
333 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
334 errmsg("must be owner of large object %u", lobjId)));
335
336 /*
337 * If there are any open LO FDs referencing that ID, close 'em.
338 */
339 if (fscxt != NULL)
340 {
341 int i;
342
343 for (i = 0; i < cookies_size; i++)
344 {
345 if (cookies[i] != NULL && cookies[i]->id == lobjId)
346 closeLOfd(i);
347 }
348 }
349
350 /*
351 * inv_drop does not create a need for end-of-transaction cleanup and
352 * hence we don't need to set lo_cleanup_needed.
353 */
354 PG_RETURN_INT32(inv_drop(lobjId));
355}
356
357/*****************************************************************************
358 * Read/Write using bytea
359 *****************************************************************************/
360
361Datum
363{
366 bytea *retval;
367 int totalread;
368
369 if (len < 0)
370 len = 0;
371
372 retval = (bytea *) palloc(VARHDRSZ + len);
373 totalread = lo_read(fd, VARDATA(retval), len);
374 SET_VARSIZE(retval, totalread + VARHDRSZ);
375
376 PG_RETURN_BYTEA_P(retval);
377}
378
379Datum
381{
383 bytea *wbuf = PG_GETARG_BYTEA_PP(1);
384 int bytestowrite;
385 int totalwritten;
386
387 PreventCommandIfReadOnly("lowrite()");
388
389 bytestowrite = VARSIZE_ANY_EXHDR(wbuf);
390 totalwritten = lo_write(fd, VARDATA_ANY(wbuf), bytestowrite);
391 PG_RETURN_INT32(totalwritten);
392}
393
394/*****************************************************************************
395 * Import/Export of Large Object
396 *****************************************************************************/
397
398/*
399 * lo_import -
400 * imports a file as an (inversion) large object.
401 */
402Datum
404{
406
408}
409
410/*
411 * lo_import_with_oid -
412 * imports a file as an (inversion) large object specifying oid.
413 */
414Datum
416{
418 Oid oid = PG_GETARG_OID(1);
419
421}
422
423static Oid
425{
426 int fd;
427 int nbytes,
429 char buf[BUFSIZE];
430 char fnamebuf[MAXPGPATH];
431 LargeObjectDesc *lobj;
432 Oid oid;
433
434 PreventCommandIfReadOnly("lo_import()");
435
436 /*
437 * open the file to be read in
438 */
439 text_to_cstring_buffer(filename, fnamebuf, sizeof(fnamebuf));
440 fd = OpenTransientFile(fnamebuf, O_RDONLY | PG_BINARY);
441 if (fd < 0)
444 errmsg("could not open server file \"%s\": %m",
445 fnamebuf)));
446
447 /*
448 * create an inversion object
449 */
450 lo_cleanup_needed = true;
451 oid = inv_create(lobjOid);
452
453 /*
454 * read in from the filesystem and write to the inversion object
455 */
457
458 while ((nbytes = read(fd, buf, BUFSIZE)) > 0)
459 {
460 tmp = inv_write(lobj, buf, nbytes);
461 Assert(tmp == nbytes);
462 }
463
464 if (nbytes < 0)
467 errmsg("could not read server file \"%s\": %m",
468 fnamebuf)));
469
470 inv_close(lobj);
471
472 if (CloseTransientFile(fd) != 0)
475 errmsg("could not close file \"%s\": %m",
476 fnamebuf)));
477
478 return oid;
479}
480
481/*
482 * lo_export -
483 * exports an (inversion) large object.
484 */
485Datum
487{
488 Oid lobjId = PG_GETARG_OID(0);
490 int fd;
491 int nbytes,
492 tmp;
493 char buf[BUFSIZE];
494 char fnamebuf[MAXPGPATH];
495 LargeObjectDesc *lobj;
496 mode_t oumask;
497
498 /*
499 * open the inversion object (no need to test for failure)
500 */
501 lo_cleanup_needed = true;
502 lobj = inv_open(lobjId, INV_READ, CurrentMemoryContext);
503
504 /*
505 * open the file to be written to
506 *
507 * Note: we reduce backend's normal 077 umask to the slightly friendlier
508 * 022. This code used to drop it all the way to 0, but creating
509 * world-writable export files doesn't seem wise.
510 */
511 text_to_cstring_buffer(filename, fnamebuf, sizeof(fnamebuf));
512 oumask = umask(S_IWGRP | S_IWOTH);
513 PG_TRY();
514 {
515 fd = OpenTransientFilePerm(fnamebuf, O_CREAT | O_WRONLY | O_TRUNC | PG_BINARY,
517 }
518 PG_FINALLY();
519 {
520 umask(oumask);
521 }
522 PG_END_TRY();
523 if (fd < 0)
526 errmsg("could not create server file \"%s\": %m",
527 fnamebuf)));
528
529 /*
530 * read in from the inversion file and write to the filesystem
531 */
532 while ((nbytes = inv_read(lobj, buf, BUFSIZE)) > 0)
533 {
534 tmp = write(fd, buf, nbytes);
535 if (tmp != nbytes)
538 errmsg("could not write server file \"%s\": %m",
539 fnamebuf)));
540 }
541
542 if (CloseTransientFile(fd) != 0)
545 errmsg("could not close file \"%s\": %m",
546 fnamebuf)));
547
548 inv_close(lobj);
549
551}
552
553/*
554 * lo_truncate -
555 * truncate a large object to a specified length
556 */
557static void
559{
560 LargeObjectDesc *lobj;
561
562 if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL)
564 (errcode(ERRCODE_UNDEFINED_OBJECT),
565 errmsg("invalid large-object descriptor: %d", fd)));
566 lobj = cookies[fd];
567
568 /* see comment in lo_read() */
569 if ((lobj->flags & IFS_WRLOCK) == 0)
571 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
572 errmsg("large object descriptor %d was not opened for writing",
573 fd)));
574
575 inv_truncate(lobj, len);
576}
577
578Datum
580{
583
584 PreventCommandIfReadOnly("lo_truncate()");
585
588}
589
590Datum
592{
595
596 PreventCommandIfReadOnly("lo_truncate64()");
597
600}
601
602/*
603 * AtEOXact_LargeObject -
604 * prepares large objects for transaction commit
605 */
606void
608{
609 int i;
610
612 return; /* no LO operations in this xact */
613
614 /*
615 * Close LO fds and clear cookies array so that LO fds are no longer good.
616 * The memory context and resource owner holding them are going away at
617 * the end-of-transaction anyway, but on commit, we need to close them to
618 * avoid warnings about leaked resources at commit. On abort we can skip
619 * this step.
620 */
621 if (isCommit)
622 {
623 for (i = 0; i < cookies_size; i++)
624 {
625 if (cookies[i] != NULL)
626 closeLOfd(i);
627 }
628 }
629
630 /* Needn't actually pfree since we're about to zap context */
631 cookies = NULL;
632 cookies_size = 0;
633
634 /* Release the LO memory context to prevent permanent memory leaks. */
635 if (fscxt)
637 fscxt = NULL;
638
639 /* Give inv_api.c a chance to clean up, too */
640 close_lo_relation(isCommit);
641
642 lo_cleanup_needed = false;
643}
644
645/*
646 * AtEOSubXact_LargeObject
647 * Take care of large objects at subtransaction commit/abort
648 *
649 * Reassign LOs created/opened during a committing subtransaction
650 * to the parent subtransaction. On abort, just close them.
651 */
652void
654 SubTransactionId parentSubid)
655{
656 int i;
657
658 if (fscxt == NULL) /* no LO operations in this xact */
659 return;
660
661 for (i = 0; i < cookies_size; i++)
662 {
664
665 if (lo != NULL && lo->subid == mySubid)
666 {
667 if (isCommit)
668 lo->subid = parentSubid;
669 else
670 closeLOfd(i);
671 }
672 }
673}
674
675/*****************************************************************************
676 * Support routines for this file
677 *****************************************************************************/
678
679static int
681{
682 int i,
683 newsize;
684
685 lo_cleanup_needed = true;
686 if (fscxt == NULL)
688 "Filesystem",
690
691 /* Try to find a free slot */
692 for (i = 0; i < cookies_size; i++)
693 {
694 if (cookies[i] == NULL)
695 return i;
696 }
697
698 /* No free slot, so make the array bigger */
699 if (cookies_size <= 0)
700 {
701 /* First time through, arbitrarily make 64-element array */
702 i = 0;
703 newsize = 64;
705 MemoryContextAllocZero(fscxt, newsize * sizeof(LargeObjectDesc *));
706 }
707 else
708 {
709 /* Double size of array */
710 i = cookies_size;
711 newsize = cookies_size * 2;
712 cookies =
714 }
715 cookies_size = newsize;
716
717 return i;
718}
719
720static void
722{
723 LargeObjectDesc *lobj;
724
725 /*
726 * Make sure we do not try to free twice if this errors out for some
727 * reason. Better a leak than a crash.
728 */
729 lobj = cookies[fd];
730 cookies[fd] = NULL;
731
732 if (lobj->snapshot)
735 inv_close(lobj);
736}
737
738/*****************************************************************************
739 * Wrappers oriented toward SQL callers
740 *****************************************************************************/
741
742/*
743 * Read [offset, offset+nbytes) within LO; when nbytes is -1, read to end.
744 */
745static bytea *
747{
748 LargeObjectDesc *loDesc;
749 int64 loSize;
750 int64 result_length;
751 int total_read PG_USED_FOR_ASSERTS_ONLY;
752 bytea *result = NULL;
753
754 lo_cleanup_needed = true;
755 loDesc = inv_open(loOid, INV_READ, CurrentMemoryContext);
756
757 /*
758 * Compute number of bytes we'll actually read, accommodating nbytes == -1
759 * and reads beyond the end of the LO.
760 */
761 loSize = inv_seek(loDesc, 0, SEEK_END);
762 if (loSize > offset)
763 {
764 if (nbytes >= 0 && nbytes <= loSize - offset)
765 result_length = nbytes; /* request is wholly inside LO */
766 else
767 result_length = loSize - offset; /* adjust to end of LO */
768 }
769 else
770 result_length = 0; /* request is wholly outside LO */
771
772 /*
773 * A result_length calculated from loSize may not fit in a size_t. Check
774 * that the size will satisfy this and subsequently-enforced size limits.
775 */
776 if (result_length > MaxAllocSize - VARHDRSZ)
778 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
779 errmsg("large object read request is too large")));
780
781 result = (bytea *) palloc(VARHDRSZ + result_length);
782
783 inv_seek(loDesc, offset, SEEK_SET);
784 total_read = inv_read(loDesc, VARDATA(result), result_length);
785 Assert(total_read == result_length);
786 SET_VARSIZE(result, result_length + VARHDRSZ);
787
788 inv_close(loDesc);
789
790 return result;
791}
792
793/*
794 * Read entire LO
795 */
796Datum
798{
799 Oid loOid = PG_GETARG_OID(0);
800 bytea *result;
801
802 result = lo_get_fragment_internal(loOid, 0, -1);
803
804 PG_RETURN_BYTEA_P(result);
805}
806
807/*
808 * Read range within LO
809 */
810Datum
812{
813 Oid loOid = PG_GETARG_OID(0);
814 int64 offset = PG_GETARG_INT64(1);
815 int32 nbytes = PG_GETARG_INT32(2);
816 bytea *result;
817
818 if (nbytes < 0)
820 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
821 errmsg("requested length cannot be negative")));
822
823 result = lo_get_fragment_internal(loOid, offset, nbytes);
824
825 PG_RETURN_BYTEA_P(result);
826}
827
828/*
829 * Create LO with initial contents given by a bytea argument
830 */
831Datum
833{
834 Oid loOid = PG_GETARG_OID(0);
836 LargeObjectDesc *loDesc;
837 int written PG_USED_FOR_ASSERTS_ONLY;
838
839 PreventCommandIfReadOnly("lo_from_bytea()");
840
841 lo_cleanup_needed = true;
842 loOid = inv_create(loOid);
843 loDesc = inv_open(loOid, INV_WRITE, CurrentMemoryContext);
844 written = inv_write(loDesc, VARDATA_ANY(str), VARSIZE_ANY_EXHDR(str));
845 Assert(written == VARSIZE_ANY_EXHDR(str));
846 inv_close(loDesc);
847
848 PG_RETURN_OID(loOid);
849}
850
851/*
852 * Update range within LO
853 */
854Datum
856{
857 Oid loOid = PG_GETARG_OID(0);
858 int64 offset = PG_GETARG_INT64(1);
860 LargeObjectDesc *loDesc;
861 int written PG_USED_FOR_ASSERTS_ONLY;
862
863 PreventCommandIfReadOnly("lo_put()");
864
865 lo_cleanup_needed = true;
866 loDesc = inv_open(loOid, INV_WRITE, CurrentMemoryContext);
867 inv_seek(loDesc, offset, SEEK_SET);
868 written = inv_write(loDesc, VARDATA_ANY(str), VARSIZE_ANY_EXHDR(str));
869 Assert(written == VARSIZE_ANY_EXHDR(str));
870 inv_close(loDesc);
871
873}
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition: aclchk.c:4058
static bytea * lo_get_fragment_internal(Oid loOid, int64 offset, int32 nbytes)
Definition: be-fsstubs.c:746
Datum be_lo_lseek(PG_FUNCTION_ARGS)
Definition: be-fsstubs.c:206
Datum be_loread(PG_FUNCTION_ARGS)
Definition: be-fsstubs.c:362
static MemoryContext fscxt
Definition: be-fsstubs.c:75
Datum be_lo_get(PG_FUNCTION_ARGS)
Definition: be-fsstubs.c:797
static void closeLOfd(int fd)
Definition: be-fsstubs.c:721
Datum be_lo_export(PG_FUNCTION_ARGS)
Definition: be-fsstubs.c:486
void AtEOXact_LargeObject(bool isCommit)
Definition: be-fsstubs.c:607
Datum be_lo_unlink(PG_FUNCTION_ARGS)
Definition: be-fsstubs.c:314
Datum be_lo_import_with_oid(PG_FUNCTION_ARGS)
Definition: be-fsstubs.c:415
Datum be_lo_truncate64(PG_FUNCTION_ARGS)
Definition: be-fsstubs.c:591
Datum be_lo_lseek64(PG_FUNCTION_ARGS)
Definition: be-fsstubs.c:231
Datum be_lo_tell64(PG_FUNCTION_ARGS)
Definition: be-fsstubs.c:298
int lo_write(int fd, const char *buf, int len)
Definition: be-fsstubs.c:182
Datum be_lo_from_bytea(PG_FUNCTION_ARGS)
Definition: be-fsstubs.c:832
int lo_read(int fd, char *buf, int len)
Definition: be-fsstubs.c:154
static Oid lo_import_internal(text *filename, Oid lobjOid)
Definition: be-fsstubs.c:424
Datum be_lowrite(PG_FUNCTION_ARGS)
Definition: be-fsstubs.c:380
static int newLOfd(void)
Definition: be-fsstubs.c:680
Datum be_lo_creat(PG_FUNCTION_ARGS)
Definition: be-fsstubs.c:249
Datum be_lo_put(PG_FUNCTION_ARGS)
Definition: be-fsstubs.c:855
Datum be_lo_truncate(PG_FUNCTION_ARGS)
Definition: be-fsstubs.c:579
Datum be_lo_create(PG_FUNCTION_ARGS)
Definition: be-fsstubs.c:262
static bool lo_cleanup_needed
Definition: be-fsstubs.c:74
Datum be_lo_tell(PG_FUNCTION_ARGS)
Definition: be-fsstubs.c:275
Datum be_lo_import(PG_FUNCTION_ARGS)
Definition: be-fsstubs.c:403
Datum be_lo_get_fragment(PG_FUNCTION_ARGS)
Definition: be-fsstubs.c:811
static LargeObjectDesc ** cookies
Definition: be-fsstubs.c:71
Datum be_lo_close(PG_FUNCTION_ARGS)
Definition: be-fsstubs.c:126
static void lo_truncate_internal(int32 fd, int64 len)
Definition: be-fsstubs.c:558
static int cookies_size
Definition: be-fsstubs.c:72
void AtEOSubXact_LargeObject(bool isCommit, SubTransactionId mySubid, SubTransactionId parentSubid)
Definition: be-fsstubs.c:653
#define BUFSIZE
Definition: be-fsstubs.c:61
Datum be_lo_open(PG_FUNCTION_ARGS)
Definition: be-fsstubs.c:87
uint32 SubTransactionId
Definition: c.h:610
#define PG_USED_FOR_ASSERTS_ONLY
Definition: c.h:201
#define VARHDRSZ
Definition: c.h:646
#define Assert(condition)
Definition: c.h:812
int64_t int64
Definition: c.h:482
#define PG_BINARY
Definition: c.h:1227
int32_t int32
Definition: c.h:481
int errcode_for_file_access(void)
Definition: elog.c:876
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define PG_TRY(...)
Definition: elog.h:371
#define PG_END_TRY(...)
Definition: elog.h:396
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
#define PG_FINALLY(...)
Definition: elog.h:388
#define ereport(elevel,...)
Definition: elog.h:149
#define DEBUG4
Definition: elog.h:27
int CloseTransientFile(int fd)
Definition: fd.c:2831
int OpenTransientFile(const char *fileName, int fileFlags)
Definition: fd.c:2655
int OpenTransientFilePerm(const char *fileName, int fileFlags, mode_t fileMode)
Definition: fd.c:2664
#define MaxAllocSize
Definition: fe_memutils.h:22
#define PG_RETURN_VOID()
Definition: fmgr.h:349
#define PG_GETARG_OID(n)
Definition: fmgr.h:275
#define PG_GETARG_BYTEA_PP(n)
Definition: fmgr.h:308
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:309
#define PG_RETURN_BYTEA_P(x)
Definition: fmgr.h:371
#define PG_RETURN_INT64(x)
Definition: fmgr.h:368
#define PG_GETARG_INT64(n)
Definition: fmgr.h:283
#define PG_RETURN_INT32(x)
Definition: fmgr.h:354
#define PG_GETARG_INT32(n)
Definition: fmgr.h:269
#define PG_RETURN_OID(x)
Definition: fmgr.h:360
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
const char * str
#define write(a, b, c)
Definition: win32.h:14
#define read(a, b, c)
Definition: win32.h:13
LargeObjectDesc * inv_open(Oid lobjId, int flags, MemoryContext mcxt)
Definition: inv_api.c:215
void inv_truncate(LargeObjectDesc *obj_desc, int64 len)
Definition: inv_api.c:740
int inv_read(LargeObjectDesc *obj_desc, char *buf, int nbytes)
Definition: inv_api.c:450
Oid inv_create(Oid lobjId)
Definition: inv_api.c:173
int64 inv_seek(LargeObjectDesc *obj_desc, int64 offset, int whence)
Definition: inv_api.c:388
void close_lo_relation(bool isCommit)
Definition: inv_api.c:97
int inv_write(LargeObjectDesc *obj_desc, const char *buf, int nbytes)
Definition: inv_api.c:543
int64 inv_tell(LargeObjectDesc *obj_desc)
Definition: inv_api.c:437
bool lo_compat_privileges
Definition: inv_api.c:56
void inv_close(LargeObjectDesc *obj_desc)
Definition: inv_api.c:299
int inv_drop(Oid lobjId)
Definition: inv_api.c:311
int i
Definition: isn.c:72
#define IFS_RDLOCK
Definition: large_object.h:48
#define IFS_WRLOCK
Definition: large_object.h:49
#define INV_READ
Definition: libpq-fs.h:22
#define INV_WRITE
Definition: libpq-fs.h:21
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:1215
MemoryContext TopMemoryContext
Definition: mcxt.c:149
void * palloc(Size size)
Definition: mcxt.c:1317
MemoryContext CurrentMemoryContext
Definition: mcxt.c:143
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:454
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:160
Oid GetUserId(void)
Definition: miscinit.c:517
#define repalloc0_array(pointer, type, oldcount, count)
Definition: palloc.h:109
static PgChecksumMode mode
Definition: pg_checksums.c:55
#define MAXPGPATH
const void size_t len
static char * filename
Definition: pg_dumpall.c:119
bool LargeObjectExists(Oid loid)
static char * buf
Definition: pg_test_fsync.c:72
uintptr_t Datum
Definition: postgres.h:64
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
static int fd(const char *x, int i)
Definition: preproc-init.c:105
ResourceOwner TopTransactionResourceOwner
Definition: resowner.c:167
void UnregisterSnapshotFromOwner(Snapshot snapshot, ResourceOwner owner)
Definition: snapmgr.c:807
Snapshot RegisterSnapshotOnOwner(Snapshot snapshot, ResourceOwner owner)
Definition: snapmgr.c:765
Snapshot snapshot
Definition: large_object.h:42
SubTransactionId subid
Definition: large_object.h:43
Definition: c.h:641
void PreventCommandIfReadOnly(const char *cmdname)
Definition: utility.c:404
#define VARDATA(PTR)
Definition: varatt.h:278
#define VARDATA_ANY(PTR)
Definition: varatt.h:324
#define SET_VARSIZE(PTR, len)
Definition: varatt.h:305
#define VARSIZE_ANY_EXHDR(PTR)
Definition: varatt.h:317
void text_to_cstring_buffer(const text *src, char *dst, size_t dst_len)
Definition: varlena.c:248
#define S_IROTH
Definition: win32_port.h:311
#define S_IRGRP
Definition: win32_port.h:299
#define S_IWOTH
Definition: win32_port.h:314
#define S_IRUSR
Definition: win32_port.h:287
#define S_IWUSR
Definition: win32_port.h:290
#define S_IWGRP
Definition: win32_port.h:302
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:790