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