PostgreSQL Source Code  git master
inv_api.c File Reference
#include "postgres.h"
#include <limits.h>
#include "access/detoast.h"
#include "access/genam.h"
#include "access/htup_details.h"
#include "access/sysattr.h"
#include "access/table.h"
#include "access/xact.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_largeobject.h"
#include "catalog/pg_largeobject_metadata.h"
#include "libpq/libpq-fs.h"
#include "miscadmin.h"
#include "storage/large_object.h"
#include "utils/acl.h"
#include "utils/fmgroids.h"
#include "utils/rel.h"
#include "utils/snapmgr.h"
Include dependency graph for inv_api.c:

Go to the source code of this file.

Functions

static void open_lo_relation (void)
 
void close_lo_relation (bool isCommit)
 
static bool myLargeObjectExists (Oid loid, Snapshot snapshot)
 
static void getdatafield (Form_pg_largeobject tuple, bytea **pdatafield, int *plen, bool *pfreeit)
 
Oid inv_create (Oid lobjId)
 
LargeObjectDescinv_open (Oid lobjId, int flags, MemoryContext mcxt)
 
void inv_close (LargeObjectDesc *obj_desc)
 
int inv_drop (Oid lobjId)
 
static uint64 inv_getsize (LargeObjectDesc *obj_desc)
 
int64 inv_seek (LargeObjectDesc *obj_desc, int64 offset, int whence)
 
int64 inv_tell (LargeObjectDesc *obj_desc)
 
int inv_read (LargeObjectDesc *obj_desc, char *buf, int nbytes)
 
int inv_write (LargeObjectDesc *obj_desc, const char *buf, int nbytes)
 
void inv_truncate (LargeObjectDesc *obj_desc, int64 len)
 

Variables

bool lo_compat_privileges
 
static Relation lo_heap_r = NULL
 
static Relation lo_index_r = NULL
 

Function Documentation

◆ close_lo_relation()

void close_lo_relation ( bool  isCommit)

Definition at line 99 of file inv_api.c.

References CurrentResourceOwner, index_close(), NoLock, table_close(), and TopTransactionResourceOwner.

Referenced by AtEOXact_LargeObject().

100 {
101  if (lo_heap_r || lo_index_r)
102  {
103  /*
104  * Only bother to close if committing; else abort cleanup will handle
105  * it
106  */
107  if (isCommit)
108  {
109  ResourceOwner currentOwner;
110 
111  currentOwner = CurrentResourceOwner;
113 
114  if (lo_index_r)
116  if (lo_heap_r)
118 
119  CurrentResourceOwner = currentOwner;
120  }
121  lo_heap_r = NULL;
122  lo_index_r = NULL;
123  }
124 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
ResourceOwner TopTransactionResourceOwner
Definition: resowner.c:144
ResourceOwner CurrentResourceOwner
Definition: resowner.c:142
static Relation lo_heap_r
Definition: inv_api.c:67
static Relation lo_index_r
Definition: inv_api.c:68
#define NoLock
Definition: lockdefs.h:34
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:158

◆ getdatafield()

static void getdatafield ( Form_pg_largeobject  tuple,
bytea **  pdatafield,
int *  plen,
bool pfreeit 
)
static

Definition at line 170 of file inv_api.c.

References detoast_attr(), ereport, errcode(), ERRCODE_DATA_CORRUPTED, errmsg(), ERROR, LOBLKSIZE, VARATT_IS_EXTENDED, VARHDRSZ, and VARSIZE.

Referenced by inv_getsize(), inv_read(), inv_truncate(), and inv_write().

174 {
175  bytea *datafield;
176  int len;
177  bool freeit;
178 
179  datafield = &(tuple->data); /* see note at top of file */
180  freeit = false;
181  if (VARATT_IS_EXTENDED(datafield))
182  {
183  datafield = (bytea *)
184  detoast_attr((struct varlena *) datafield);
185  freeit = true;
186  }
187  len = VARSIZE(datafield) - VARHDRSZ;
188  if (len < 0 || len > LOBLKSIZE)
189  ereport(ERROR,
191  errmsg("pg_largeobject entry for OID %u, page %d has invalid data field size %d",
192  tuple->loid, tuple->pageno, len)));
193  *pdatafield = datafield;
194  *plen = len;
195  *pfreeit = freeit;
196 }
#define LOBLKSIZE
Definition: large_object.h:70
#define VARSIZE(PTR)
Definition: postgres.h:303
#define VARHDRSZ
Definition: c.h:568
int errcode(int sqlerrcode)
Definition: elog.c:610
struct varlena * detoast_attr(struct varlena *attr)
Definition: detoast.c:115
#define ERROR
Definition: elog.h:43
#define ERRCODE_DATA_CORRUPTED
Definition: pg_basebackup.c:45
#define ereport(elevel,...)
Definition: elog.h:144
#define VARATT_IS_EXTENDED(PTR)
Definition: postgres.h:327
int errmsg(const char *fmt,...)
Definition: elog.c:824
Definition: c.h:562

◆ inv_close()

void inv_close ( LargeObjectDesc obj_desc)

Definition at line 340 of file inv_api.c.

References Assert, pfree(), PointerIsValid, LargeObjectDesc::snapshot, TopTransactionResourceOwner, and UnregisterSnapshotFromOwner().

Referenced by AtEOSubXact_LargeObject(), AtEOXact_LargeObject(), be_lo_close(), be_lo_export(), be_lo_from_bytea(), be_lo_put(), be_lo_unlink(), lo_get_fragment_internal(), and lo_import_internal().

341 {
342  Assert(PointerIsValid(obj_desc));
343 
346 
347  pfree(obj_desc);
348 }
ResourceOwner TopTransactionResourceOwner
Definition: resowner.c:144
void pfree(void *pointer)
Definition: mcxt.c:1057
Snapshot snapshot
Definition: large_object.h:42
#define Assert(condition)
Definition: c.h:745
void UnregisterSnapshotFromOwner(Snapshot snapshot, ResourceOwner owner)
Definition: snapmgr.c:865
#define PointerIsValid(pointer)
Definition: c.h:639

◆ inv_create()

Oid inv_create ( Oid  lobjId)

Definition at line 212 of file inv_api.c.

References CommandCounterIncrement(), GetUserId(), InvokeObjectPostCreateHook, LargeObjectCreate(), and recordDependencyOnOwner().

Referenced by be_lo_creat(), be_lo_create(), be_lo_from_bytea(), and lo_import_internal().

213 {
214  Oid lobjId_new;
215 
216  /*
217  * Create a new largeobject with empty data pages
218  */
219  lobjId_new = LargeObjectCreate(lobjId);
220 
221  /*
222  * dependency on the owner of largeobject
223  *
224  * The reason why we use LargeObjectRelationId instead of
225  * LargeObjectMetadataRelationId here is to provide backward compatibility
226  * to the applications which utilize a knowledge about internal layout of
227  * system catalogs. OID of pg_largeobject_metadata and loid of
228  * pg_largeobject are same value, so there are no actual differences here.
229  */
230  recordDependencyOnOwner(LargeObjectRelationId,
231  lobjId_new, GetUserId());
232 
233  /* Post creation hook for new large object */
234  InvokeObjectPostCreateHook(LargeObjectRelationId, lobjId_new, 0);
235 
236  /*
237  * Advance command counter to make new tuple visible to later operations.
238  */
240 
241  return lobjId_new;
242 }
#define InvokeObjectPostCreateHook(classId, objectId, subId)
Definition: objectaccess.h:151
Oid GetUserId(void)
Definition: miscinit.c:476
void recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner)
Definition: pg_shdepend.c:164
Oid LargeObjectCreate(Oid loid)
unsigned int Oid
Definition: postgres_ext.h:31
void CommandCounterIncrement(void)
Definition: xact.c:1021

◆ inv_drop()

int inv_drop ( Oid  lobjId)

Definition at line 356 of file inv_api.c.

References ObjectAddress::classId, CommandCounterIncrement(), DROP_CASCADE, and performDeletion().

Referenced by be_lo_unlink().

357 {
358  ObjectAddress object;
359 
360  /*
361  * Delete any comments and dependencies on the large object
362  */
363  object.classId = LargeObjectRelationId;
364  object.objectId = lobjId;
365  object.objectSubId = 0;
366  performDeletion(&object, DROP_CASCADE, 0);
367 
368  /*
369  * Advance command counter so that tuple removal will be seen by later
370  * large-object operations in this transaction.
371  */
373 
374  /* For historical reasons, we always return 1 on success. */
375  return 1;
376 }
void performDeletion(const ObjectAddress *object, DropBehavior behavior, int flags)
Definition: dependency.c:312
void CommandCounterIncrement(void)
Definition: xact.c:1021

◆ inv_getsize()

static uint64 inv_getsize ( LargeObjectDesc obj_desc)
static

Definition at line 385 of file inv_api.c.

References Assert, BackwardScanDirection, BTEqualStrategyNumber, elog, ERROR, getdatafield(), GETSTRUCT, HeapTupleHasNulls, HeapTupleIsValid, LargeObjectDesc::id, LOBLKSIZE, ObjectIdGetDatum, open_lo_relation(), pfree(), PointerIsValid, ScanKeyInit(), LargeObjectDesc::snapshot, systable_beginscan_ordered(), systable_endscan_ordered(), and systable_getnext_ordered().

Referenced by inv_seek().

386 {
387  uint64 lastbyte = 0;
388  ScanKeyData skey[1];
389  SysScanDesc sd;
390  HeapTuple tuple;
391 
392  Assert(PointerIsValid(obj_desc));
393 
395 
396  ScanKeyInit(&skey[0],
397  Anum_pg_largeobject_loid,
398  BTEqualStrategyNumber, F_OIDEQ,
399  ObjectIdGetDatum(obj_desc->id));
400 
402  obj_desc->snapshot, 1, skey);
403 
404  /*
405  * Because the pg_largeobject index is on both loid and pageno, but we
406  * constrain only loid, a backwards scan should visit all pages of the
407  * large object in reverse pageno order. So, it's sufficient to examine
408  * the first valid tuple (== last valid page).
409  */
411  if (HeapTupleIsValid(tuple))
412  {
413  Form_pg_largeobject data;
414  bytea *datafield;
415  int len;
416  bool pfreeit;
417 
418  if (HeapTupleHasNulls(tuple)) /* paranoia */
419  elog(ERROR, "null field found in pg_largeobject");
420  data = (Form_pg_largeobject) GETSTRUCT(tuple);
421  getdatafield(data, &datafield, &len, &pfreeit);
422  lastbyte = (uint64) data->pageno * LOBLKSIZE + len;
423  if (pfreeit)
424  pfree(datafield);
425  }
426 
428 
429  return lastbyte;
430 }
static void open_lo_relation(void)
Definition: inv_api.c:75
#define LOBLKSIZE
Definition: large_object.h:70
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
HeapTuple systable_getnext_ordered(SysScanDesc sysscan, ScanDirection direction)
Definition: genam.c:681
static Relation lo_heap_r
Definition: inv_api.c:67
static Relation lo_index_r
Definition: inv_api.c:68
void pfree(void *pointer)
Definition: mcxt.c:1057
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
Snapshot snapshot
Definition: large_object.h:42
#define HeapTupleHasNulls(tuple)
Definition: htup_details.h:661
void systable_endscan_ordered(SysScanDesc sysscan)
Definition: genam.c:706
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:745
static void getdatafield(Form_pg_largeobject tuple, bytea **pdatafield, int *plen, bool *pfreeit)
Definition: inv_api.c:170
SysScanDesc systable_beginscan_ordered(Relation heapRelation, Relation indexRelation, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:616
#define elog(elevel,...)
Definition: elog.h:214
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
Definition: c.h:562
FormData_pg_largeobject * Form_pg_largeobject
#define PointerIsValid(pointer)
Definition: c.h:639
#define BTEqualStrategyNumber
Definition: stratnum.h:31

◆ inv_open()

LargeObjectDesc* inv_open ( Oid  lobjId,
int  flags,
MemoryContext  mcxt 
)

Definition at line 253 of file inv_api.c.

References ACL_SELECT, ACL_UPDATE, ACLCHECK_OK, ereport, errcode(), errmsg(), ERROR, LargeObjectDesc::flags, GetActiveSnapshot(), GetCurrentSubTransactionId(), GetUserId(), LargeObjectDesc::id, IFS_RDLOCK, IFS_WRLOCK, INV_READ, INV_WRITE, lo_compat_privileges, MemoryContextAlloc(), myLargeObjectExists(), LargeObjectDesc::offset, pg_largeobject_aclcheck_snapshot(), RegisterSnapshotOnOwner(), LargeObjectDesc::snapshot, LargeObjectDesc::subid, and TopTransactionResourceOwner.

Referenced by be_lo_export(), be_lo_from_bytea(), be_lo_open(), be_lo_put(), lo_get_fragment_internal(), and lo_import_internal().

254 {
255  LargeObjectDesc *retval;
256  Snapshot snapshot = NULL;
257  int descflags = 0;
258 
259  /*
260  * Historically, no difference is made between (INV_WRITE) and (INV_WRITE
261  * | INV_READ), the caller being allowed to read the large object
262  * descriptor in either case.
263  */
264  if (flags & INV_WRITE)
265  descflags |= IFS_WRLOCK | IFS_RDLOCK;
266  if (flags & INV_READ)
267  descflags |= IFS_RDLOCK;
268 
269  if (descflags == 0)
270  ereport(ERROR,
271  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
272  errmsg("invalid flags for opening a large object: %d",
273  flags)));
274 
275  /* Get snapshot. If write is requested, use an instantaneous snapshot. */
276  if (descflags & IFS_WRLOCK)
277  snapshot = NULL;
278  else
279  snapshot = GetActiveSnapshot();
280 
281  /* Can't use LargeObjectExists here because we need to specify snapshot */
282  if (!myLargeObjectExists(lobjId, snapshot))
283  ereport(ERROR,
284  (errcode(ERRCODE_UNDEFINED_OBJECT),
285  errmsg("large object %u does not exist", lobjId)));
286 
287  /* Apply permission checks, again specifying snapshot */
288  if ((descflags & IFS_RDLOCK) != 0)
289  {
290  if (!lo_compat_privileges &&
292  GetUserId(),
293  ACL_SELECT,
294  snapshot) != ACLCHECK_OK)
295  ereport(ERROR,
296  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
297  errmsg("permission denied for large object %u",
298  lobjId)));
299  }
300  if ((descflags & IFS_WRLOCK) != 0)
301  {
302  if (!lo_compat_privileges &&
304  GetUserId(),
305  ACL_UPDATE,
306  snapshot) != ACLCHECK_OK)
307  ereport(ERROR,
308  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
309  errmsg("permission denied for large object %u",
310  lobjId)));
311  }
312 
313  /* OK to create a descriptor */
314  retval = (LargeObjectDesc *) MemoryContextAlloc(mcxt,
315  sizeof(LargeObjectDesc));
316  retval->id = lobjId;
317  retval->subid = GetCurrentSubTransactionId();
318  retval->offset = 0;
319  retval->flags = descflags;
320 
321  /*
322  * We must register the snapshot in TopTransaction's resowner, because it
323  * must stay alive until the LO is closed rather than until the current
324  * portal shuts down. Do this last to avoid uselessly leaking the
325  * snapshot if an error is thrown above.
326  */
327  if (snapshot)
328  snapshot = RegisterSnapshotOnOwner(snapshot,
330  retval->snapshot = snapshot;
331 
332  return retval;
333 }
static bool myLargeObjectExists(Oid loid, Snapshot snapshot)
Definition: inv_api.c:132
#define IFS_RDLOCK
Definition: large_object.h:48
bool lo_compat_privileges
Definition: inv_api.c:58
Oid GetUserId(void)
Definition: miscinit.c:476
ResourceOwner TopTransactionResourceOwner
Definition: resowner.c:144
Snapshot GetActiveSnapshot(void)
Definition: snapmgr.c:786
int errcode(int sqlerrcode)
Definition: elog.c:610
SubTransactionId subid
Definition: large_object.h:43
#define IFS_WRLOCK
Definition: large_object.h:49
#define INV_READ
Definition: libpq-fs.h:22
#define ERROR
Definition: elog.h:43
Snapshot snapshot
Definition: large_object.h:42
#define ACL_UPDATE
Definition: parsenodes.h:76
#define ACL_SELECT
Definition: parsenodes.h:75
#define ereport(elevel,...)
Definition: elog.h:144
Snapshot RegisterSnapshotOnOwner(Snapshot snapshot, ResourceOwner owner)
Definition: snapmgr.c:823
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:723
#define INV_WRITE
Definition: libpq-fs.h:21
int errmsg(const char *fmt,...)
Definition: elog.c:824
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:797
AclResult pg_largeobject_aclcheck_snapshot(Oid lobj_oid, Oid roleid, AclMode mode, Snapshot snapshot)
Definition: aclchk.c:4611

◆ inv_read()

int inv_read ( LargeObjectDesc obj_desc,
char *  buf,
int  nbytes 
)

Definition at line 495 of file inv_api.c.

References Assert, BTEqualStrategyNumber, BTGreaterEqualStrategyNumber, elog, ereport, errcode(), errmsg(), ERROR, LargeObjectDesc::flags, ForwardScanDirection, getdatafield(), GETSTRUCT, HeapTupleHasNulls, LargeObjectDesc::id, IFS_RDLOCK, Int32GetDatum, LOBLKSIZE, MemSet, ObjectIdGetDatum, LargeObjectDesc::offset, open_lo_relation(), pfree(), PointerIsValid, ScanKeyInit(), LargeObjectDesc::snapshot, systable_beginscan_ordered(), systable_endscan_ordered(), systable_getnext_ordered(), and VARDATA.

Referenced by be_lo_export(), lo_get_fragment_internal(), and lo_read().

496 {
497  int nread = 0;
498  int64 n;
499  int64 off;
500  int len;
501  int32 pageno = (int32) (obj_desc->offset / LOBLKSIZE);
502  uint64 pageoff;
503  ScanKeyData skey[2];
504  SysScanDesc sd;
505  HeapTuple tuple;
506 
507  Assert(PointerIsValid(obj_desc));
508  Assert(buf != NULL);
509 
510  if ((obj_desc->flags & IFS_RDLOCK) == 0)
511  ereport(ERROR,
512  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
513  errmsg("permission denied for large object %u",
514  obj_desc->id)));
515 
516  if (nbytes <= 0)
517  return 0;
518 
520 
521  ScanKeyInit(&skey[0],
522  Anum_pg_largeobject_loid,
523  BTEqualStrategyNumber, F_OIDEQ,
524  ObjectIdGetDatum(obj_desc->id));
525 
526  ScanKeyInit(&skey[1],
527  Anum_pg_largeobject_pageno,
529  Int32GetDatum(pageno));
530 
532  obj_desc->snapshot, 2, skey);
533 
534  while ((tuple = systable_getnext_ordered(sd, ForwardScanDirection)) != NULL)
535  {
536  Form_pg_largeobject data;
537  bytea *datafield;
538  bool pfreeit;
539 
540  if (HeapTupleHasNulls(tuple)) /* paranoia */
541  elog(ERROR, "null field found in pg_largeobject");
542  data = (Form_pg_largeobject) GETSTRUCT(tuple);
543 
544  /*
545  * We expect the indexscan will deliver pages in order. However,
546  * there may be missing pages if the LO contains unwritten "holes". We
547  * want missing sections to read out as zeroes.
548  */
549  pageoff = ((uint64) data->pageno) * LOBLKSIZE;
550  if (pageoff > obj_desc->offset)
551  {
552  n = pageoff - obj_desc->offset;
553  n = (n <= (nbytes - nread)) ? n : (nbytes - nread);
554  MemSet(buf + nread, 0, n);
555  nread += n;
556  obj_desc->offset += n;
557  }
558 
559  if (nread < nbytes)
560  {
561  Assert(obj_desc->offset >= pageoff);
562  off = (int) (obj_desc->offset - pageoff);
563  Assert(off >= 0 && off < LOBLKSIZE);
564 
565  getdatafield(data, &datafield, &len, &pfreeit);
566  if (len > off)
567  {
568  n = len - off;
569  n = (n <= (nbytes - nread)) ? n : (nbytes - nread);
570  memcpy(buf + nread, VARDATA(datafield) + off, n);
571  nread += n;
572  obj_desc->offset += n;
573  }
574  if (pfreeit)
575  pfree(datafield);
576  }
577 
578  if (nread >= nbytes)
579  break;
580  }
581 
583 
584  return nread;
585 }
static void open_lo_relation(void)
Definition: inv_api.c:75
#define LOBLKSIZE
Definition: large_object.h:70
#define IFS_RDLOCK
Definition: large_object.h:48
#define VARDATA(PTR)
Definition: postgres.h:302
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
int errcode(int sqlerrcode)
Definition: elog.c:610
#define MemSet(start, val, len)
Definition: c.h:949
HeapTuple systable_getnext_ordered(SysScanDesc sysscan, ScanDirection direction)
Definition: genam.c:681
static Relation lo_heap_r
Definition: inv_api.c:67
signed int int32
Definition: c.h:362
static Relation lo_index_r
Definition: inv_api.c:68
void pfree(void *pointer)
Definition: mcxt.c:1057
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
Snapshot snapshot
Definition: large_object.h:42
#define HeapTupleHasNulls(tuple)
Definition: htup_details.h:661
static char * buf
Definition: pg_test_fsync.c:68
void systable_endscan_ordered(SysScanDesc sysscan)
Definition: genam.c:706
#define ereport(elevel,...)
Definition: elog.h:144
#define Assert(condition)
Definition: c.h:745
static void getdatafield(Form_pg_largeobject tuple, bytea **pdatafield, int *plen, bool *pfreeit)
Definition: inv_api.c:170
#define Int32GetDatum(X)
Definition: postgres.h:479
int errmsg(const char *fmt,...)
Definition: elog.c:824
SysScanDesc systable_beginscan_ordered(Relation heapRelation, Relation indexRelation, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:616
#define elog(elevel,...)
Definition: elog.h:214
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
Definition: c.h:562
FormData_pg_largeobject * Form_pg_largeobject
#define PointerIsValid(pointer)
Definition: c.h:639
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define BTGreaterEqualStrategyNumber
Definition: stratnum.h:32

◆ inv_seek()

int64 inv_seek ( LargeObjectDesc obj_desc,
int64  offset,
int  whence 
)

Definition at line 433 of file inv_api.c.

References Assert, ereport, errcode(), errmsg(), errmsg_internal(), ERROR, INT64_FORMAT, inv_getsize(), MAX_LARGE_OBJECT_SIZE, LargeObjectDesc::offset, and PointerIsValid.

Referenced by be_lo_lseek(), be_lo_lseek64(), be_lo_put(), and lo_get_fragment_internal().

434 {
435  int64 newoffset;
436 
437  Assert(PointerIsValid(obj_desc));
438 
439  /*
440  * We allow seek/tell if you have either read or write permission, so no
441  * need for a permission check here.
442  */
443 
444  /*
445  * Note: overflow in the additions is possible, but since we will reject
446  * negative results, we don't need any extra test for that.
447  */
448  switch (whence)
449  {
450  case SEEK_SET:
451  newoffset = offset;
452  break;
453  case SEEK_CUR:
454  newoffset = obj_desc->offset + offset;
455  break;
456  case SEEK_END:
457  newoffset = inv_getsize(obj_desc) + offset;
458  break;
459  default:
460  ereport(ERROR,
461  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
462  errmsg("invalid whence setting: %d", whence)));
463  newoffset = 0; /* keep compiler quiet */
464  break;
465  }
466 
467  /*
468  * use errmsg_internal here because we don't want to expose INT64_FORMAT
469  * in translatable strings; doing better is not worth the trouble
470  */
471  if (newoffset < 0 || newoffset > MAX_LARGE_OBJECT_SIZE)
472  ereport(ERROR,
473  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
474  errmsg_internal("invalid large object seek target: " INT64_FORMAT,
475  newoffset)));
476 
477  obj_desc->offset = newoffset;
478  return newoffset;
479 }
#define MAX_LARGE_OBJECT_SIZE
Definition: large_object.h:76
int errcode(int sqlerrcode)
Definition: elog.c:610
#define ERROR
Definition: elog.h:43
static uint64 inv_getsize(LargeObjectDesc *obj_desc)
Definition: inv_api.c:385
#define ereport(elevel,...)
Definition: elog.h:144
int errmsg_internal(const char *fmt,...)
Definition: elog.c:911
#define Assert(condition)
Definition: c.h:745
#define INT64_FORMAT
Definition: c.h:416
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define PointerIsValid(pointer)
Definition: c.h:639

◆ inv_tell()

int64 inv_tell ( LargeObjectDesc obj_desc)

Definition at line 482 of file inv_api.c.

References Assert, LargeObjectDesc::offset, and PointerIsValid.

Referenced by be_lo_tell(), and be_lo_tell64().

483 {
484  Assert(PointerIsValid(obj_desc));
485 
486  /*
487  * We allow seek/tell if you have either read or write permission, so no
488  * need for a permission check here.
489  */
490 
491  return obj_desc->offset;
492 }
#define Assert(condition)
Definition: c.h:745
#define PointerIsValid(pointer)
Definition: c.h:639

◆ inv_truncate()

void inv_truncate ( LargeObjectDesc obj_desc,
int64  len 
)

Definition at line 785 of file inv_api.c.

References Assert, BTEqualStrategyNumber, BTGreaterEqualStrategyNumber, CatalogCloseIndexes(), CatalogOpenIndexes(), CatalogTupleDelete(), CatalogTupleInsertWithInfo(), CatalogTupleUpdateWithInfo(), CommandCounterIncrement(), elog, ereport, errcode(), errmsg(), errmsg_internal(), ERROR, LargeObjectDesc::flags, ForwardScanDirection, getdatafield(), GETSTRUCT, heap_form_tuple(), heap_freetuple(), heap_modify_tuple(), HeapTupleHasNulls, LargeObjectDesc::id, IFS_WRLOCK, Int32GetDatum, INT64_FORMAT, LOBLKSIZE, MAX_LARGE_OBJECT_SIZE, MemSet, ObjectIdGetDatum, open_lo_relation(), pfree(), PointerGetDatum, PointerIsValid, RelationData::rd_att, RelationGetDescr, ScanKeyInit(), SET_VARSIZE, LargeObjectDesc::snapshot, systable_beginscan_ordered(), systable_endscan_ordered(), systable_getnext_ordered(), HeapTupleData::t_self, values, VARDATA, and VARHDRSZ.

Referenced by lo_truncate_internal().

786 {
787  int32 pageno = (int32) (len / LOBLKSIZE);
788  int32 off;
789  ScanKeyData skey[2];
790  SysScanDesc sd;
791  HeapTuple oldtuple;
792  Form_pg_largeobject olddata;
793  union
794  {
795  bytea hdr;
796  /* this is to make the union big enough for a LO data chunk: */
797  char data[LOBLKSIZE + VARHDRSZ];
798  /* ensure union is aligned well enough: */
799  int32 align_it;
800  } workbuf;
801  char *workb = VARDATA(&workbuf.hdr);
802  HeapTuple newtup;
803  Datum values[Natts_pg_largeobject];
804  bool nulls[Natts_pg_largeobject];
805  bool replace[Natts_pg_largeobject];
806  CatalogIndexState indstate;
807 
808  Assert(PointerIsValid(obj_desc));
809 
810  /* enforce writability because snapshot is probably wrong otherwise */
811  if ((obj_desc->flags & IFS_WRLOCK) == 0)
812  ereport(ERROR,
813  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
814  errmsg("permission denied for large object %u",
815  obj_desc->id)));
816 
817  /*
818  * use errmsg_internal here because we don't want to expose INT64_FORMAT
819  * in translatable strings; doing better is not worth the trouble
820  */
821  if (len < 0 || len > MAX_LARGE_OBJECT_SIZE)
822  ereport(ERROR,
823  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
824  errmsg_internal("invalid large object truncation target: " INT64_FORMAT,
825  len)));
826 
828 
829  indstate = CatalogOpenIndexes(lo_heap_r);
830 
831  /*
832  * Set up to find all pages with desired loid and pageno >= target
833  */
834  ScanKeyInit(&skey[0],
835  Anum_pg_largeobject_loid,
836  BTEqualStrategyNumber, F_OIDEQ,
837  ObjectIdGetDatum(obj_desc->id));
838 
839  ScanKeyInit(&skey[1],
840  Anum_pg_largeobject_pageno,
842  Int32GetDatum(pageno));
843 
845  obj_desc->snapshot, 2, skey);
846 
847  /*
848  * If possible, get the page the truncation point is in. The truncation
849  * point may be beyond the end of the LO or in a hole.
850  */
851  olddata = NULL;
852  if ((oldtuple = systable_getnext_ordered(sd, ForwardScanDirection)) != NULL)
853  {
854  if (HeapTupleHasNulls(oldtuple)) /* paranoia */
855  elog(ERROR, "null field found in pg_largeobject");
856  olddata = (Form_pg_largeobject) GETSTRUCT(oldtuple);
857  Assert(olddata->pageno >= pageno);
858  }
859 
860  /*
861  * If we found the page of the truncation point we need to truncate the
862  * data in it. Otherwise if we're in a hole, we need to create a page to
863  * mark the end of data.
864  */
865  if (olddata != NULL && olddata->pageno == pageno)
866  {
867  /* First, load old data into workbuf */
868  bytea *datafield;
869  int pagelen;
870  bool pfreeit;
871 
872  getdatafield(olddata, &datafield, &pagelen, &pfreeit);
873  memcpy(workb, VARDATA(datafield), pagelen);
874  if (pfreeit)
875  pfree(datafield);
876 
877  /*
878  * Fill any hole
879  */
880  off = len % LOBLKSIZE;
881  if (off > pagelen)
882  MemSet(workb + pagelen, 0, off - pagelen);
883 
884  /* compute length of new page */
885  SET_VARSIZE(&workbuf.hdr, off + VARHDRSZ);
886 
887  /*
888  * Form and insert updated tuple
889  */
890  memset(values, 0, sizeof(values));
891  memset(nulls, false, sizeof(nulls));
892  memset(replace, false, sizeof(replace));
893  values[Anum_pg_largeobject_data - 1] = PointerGetDatum(&workbuf);
894  replace[Anum_pg_largeobject_data - 1] = true;
895  newtup = heap_modify_tuple(oldtuple, RelationGetDescr(lo_heap_r),
896  values, nulls, replace);
897  CatalogTupleUpdateWithInfo(lo_heap_r, &newtup->t_self, newtup,
898  indstate);
899  heap_freetuple(newtup);
900  }
901  else
902  {
903  /*
904  * If the first page we found was after the truncation point, we're in
905  * a hole that we'll fill, but we need to delete the later page
906  * because the loop below won't visit it again.
907  */
908  if (olddata != NULL)
909  {
910  Assert(olddata->pageno > pageno);
911  CatalogTupleDelete(lo_heap_r, &oldtuple->t_self);
912  }
913 
914  /*
915  * Write a brand new page.
916  *
917  * Fill the hole up to the truncation point
918  */
919  off = len % LOBLKSIZE;
920  if (off > 0)
921  MemSet(workb, 0, off);
922 
923  /* compute length of new page */
924  SET_VARSIZE(&workbuf.hdr, off + VARHDRSZ);
925 
926  /*
927  * Form and insert new tuple
928  */
929  memset(values, 0, sizeof(values));
930  memset(nulls, false, sizeof(nulls));
931  values[Anum_pg_largeobject_loid - 1] = ObjectIdGetDatum(obj_desc->id);
932  values[Anum_pg_largeobject_pageno - 1] = Int32GetDatum(pageno);
933  values[Anum_pg_largeobject_data - 1] = PointerGetDatum(&workbuf);
934  newtup = heap_form_tuple(lo_heap_r->rd_att, values, nulls);
935  CatalogTupleInsertWithInfo(lo_heap_r, newtup, indstate);
936  heap_freetuple(newtup);
937  }
938 
939  /*
940  * Delete any pages after the truncation point. If the initial search
941  * didn't find a page, then of course there's nothing more to do.
942  */
943  if (olddata != NULL)
944  {
945  while ((oldtuple = systable_getnext_ordered(sd, ForwardScanDirection)) != NULL)
946  {
947  CatalogTupleDelete(lo_heap_r, &oldtuple->t_self);
948  }
949  }
950 
952 
953  CatalogCloseIndexes(indstate);
954 
955  /*
956  * Advance command counter so that tuple updates will be seen by later
957  * large-object operations in this transaction.
958  */
960 }
#define MAX_LARGE_OBJECT_SIZE
Definition: large_object.h:76
static void open_lo_relation(void)
Definition: inv_api.c:75
#define LOBLKSIZE
Definition: large_object.h:70
#define VARDATA(PTR)
Definition: postgres.h:302
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
#define RelationGetDescr(relation)
Definition: rel.h:482
#define PointerGetDatum(X)
Definition: postgres.h:556
#define VARHDRSZ
Definition: c.h:568
int errcode(int sqlerrcode)
Definition: elog.c:610
#define MemSet(start, val, len)
Definition: c.h:949
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:350
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
HeapTuple systable_getnext_ordered(SysScanDesc sysscan, ScanDirection direction)
Definition: genam.c:681
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
static Relation lo_heap_r
Definition: inv_api.c:67
#define IFS_WRLOCK
Definition: large_object.h:49
signed int int32
Definition: c.h:362
static Relation lo_index_r
Definition: inv_api.c:68
void pfree(void *pointer)
Definition: mcxt.c:1057
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
Snapshot snapshot
Definition: large_object.h:42
ItemPointerData t_self
Definition: htup.h:65
#define HeapTupleHasNulls(tuple)
Definition: htup_details.h:661
void CatalogTupleUpdateWithInfo(Relation heapRel, ItemPointer otid, HeapTuple tup, CatalogIndexState indstate)
Definition: indexing.c:324
uintptr_t Datum
Definition: postgres.h:367
void CommandCounterIncrement(void)
Definition: xact.c:1021
void CatalogTupleInsertWithInfo(Relation heapRel, HeapTuple tup, CatalogIndexState indstate)
Definition: indexing.c:244
void systable_endscan_ordered(SysScanDesc sysscan)
Definition: genam.c:706
TupleDesc rd_att
Definition: rel.h:110
#define ereport(elevel,...)
Definition: elog.h:144
int errmsg_internal(const char *fmt,...)
Definition: elog.c:911
#define Assert(condition)
Definition: c.h:745
static void getdatafield(Form_pg_largeobject tuple, bytea **pdatafield, int *plen, bool *pfreeit)
Definition: inv_api.c:170
CatalogIndexState CatalogOpenIndexes(Relation heapRel)
Definition: indexing.c:43
#define INT64_FORMAT
Definition: c.h:416
static Datum values[MAXATTR]
Definition: bootstrap.c:165
#define Int32GetDatum(X)
Definition: postgres.h:479
int errmsg(const char *fmt,...)
Definition: elog.c:824
SysScanDesc systable_beginscan_ordered(Relation heapRelation, Relation indexRelation, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:616
#define elog(elevel,...)
Definition: elog.h:214
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
void CatalogCloseIndexes(CatalogIndexState indstate)
Definition: indexing.c:61
Definition: c.h:562
#define SET_VARSIZE(PTR, len)
Definition: postgres.h:329
FormData_pg_largeobject * Form_pg_largeobject
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:1113
#define PointerIsValid(pointer)
Definition: c.h:639
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define BTGreaterEqualStrategyNumber
Definition: stratnum.h:32

◆ inv_write()

int inv_write ( LargeObjectDesc obj_desc,
const char *  buf,
int  nbytes 
)

Definition at line 588 of file inv_api.c.

References Assert, BTEqualStrategyNumber, BTGreaterEqualStrategyNumber, CatalogCloseIndexes(), CatalogOpenIndexes(), CatalogTupleInsertWithInfo(), CatalogTupleUpdateWithInfo(), CommandCounterIncrement(), elog, ereport, errcode(), errmsg(), ERROR, LargeObjectDesc::flags, ForwardScanDirection, getdatafield(), GETSTRUCT, heap_form_tuple(), heap_freetuple(), heap_modify_tuple(), HeapTupleHasNulls, LargeObjectDesc::id, IFS_WRLOCK, Int32GetDatum, LOBLKSIZE, MAX_LARGE_OBJECT_SIZE, MemSet, ObjectIdGetDatum, LargeObjectDesc::offset, open_lo_relation(), pfree(), PointerGetDatum, PointerIsValid, RelationData::rd_att, RelationGetDescr, ScanKeyInit(), SET_VARSIZE, LargeObjectDesc::snapshot, systable_beginscan_ordered(), systable_endscan_ordered(), systable_getnext_ordered(), HeapTupleData::t_self, values, VARDATA, and VARHDRSZ.

Referenced by be_lo_from_bytea(), be_lo_put(), lo_import_internal(), and lo_write().

589 {
590  int nwritten = 0;
591  int n;
592  int off;
593  int len;
594  int32 pageno = (int32) (obj_desc->offset / LOBLKSIZE);
595  ScanKeyData skey[2];
596  SysScanDesc sd;
597  HeapTuple oldtuple;
598  Form_pg_largeobject olddata;
599  bool neednextpage;
600  bytea *datafield;
601  bool pfreeit;
602  union
603  {
604  bytea hdr;
605  /* this is to make the union big enough for a LO data chunk: */
606  char data[LOBLKSIZE + VARHDRSZ];
607  /* ensure union is aligned well enough: */
608  int32 align_it;
609  } workbuf;
610  char *workb = VARDATA(&workbuf.hdr);
611  HeapTuple newtup;
612  Datum values[Natts_pg_largeobject];
613  bool nulls[Natts_pg_largeobject];
614  bool replace[Natts_pg_largeobject];
615  CatalogIndexState indstate;
616 
617  Assert(PointerIsValid(obj_desc));
618  Assert(buf != NULL);
619 
620  /* enforce writability because snapshot is probably wrong otherwise */
621  if ((obj_desc->flags & IFS_WRLOCK) == 0)
622  ereport(ERROR,
623  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
624  errmsg("permission denied for large object %u",
625  obj_desc->id)));
626 
627  if (nbytes <= 0)
628  return 0;
629 
630  /* this addition can't overflow because nbytes is only int32 */
631  if ((nbytes + obj_desc->offset) > MAX_LARGE_OBJECT_SIZE)
632  ereport(ERROR,
633  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
634  errmsg("invalid large object write request size: %d",
635  nbytes)));
636 
638 
639  indstate = CatalogOpenIndexes(lo_heap_r);
640 
641  ScanKeyInit(&skey[0],
642  Anum_pg_largeobject_loid,
643  BTEqualStrategyNumber, F_OIDEQ,
644  ObjectIdGetDatum(obj_desc->id));
645 
646  ScanKeyInit(&skey[1],
647  Anum_pg_largeobject_pageno,
649  Int32GetDatum(pageno));
650 
652  obj_desc->snapshot, 2, skey);
653 
654  oldtuple = NULL;
655  olddata = NULL;
656  neednextpage = true;
657 
658  while (nwritten < nbytes)
659  {
660  /*
661  * If possible, get next pre-existing page of the LO. We expect the
662  * indexscan will deliver these in order --- but there may be holes.
663  */
664  if (neednextpage)
665  {
666  if ((oldtuple = systable_getnext_ordered(sd, ForwardScanDirection)) != NULL)
667  {
668  if (HeapTupleHasNulls(oldtuple)) /* paranoia */
669  elog(ERROR, "null field found in pg_largeobject");
670  olddata = (Form_pg_largeobject) GETSTRUCT(oldtuple);
671  Assert(olddata->pageno >= pageno);
672  }
673  neednextpage = false;
674  }
675 
676  /*
677  * If we have a pre-existing page, see if it is the page we want to
678  * write, or a later one.
679  */
680  if (olddata != NULL && olddata->pageno == pageno)
681  {
682  /*
683  * Update an existing page with fresh data.
684  *
685  * First, load old data into workbuf
686  */
687  getdatafield(olddata, &datafield, &len, &pfreeit);
688  memcpy(workb, VARDATA(datafield), len);
689  if (pfreeit)
690  pfree(datafield);
691 
692  /*
693  * Fill any hole
694  */
695  off = (int) (obj_desc->offset % LOBLKSIZE);
696  if (off > len)
697  MemSet(workb + len, 0, off - len);
698 
699  /*
700  * Insert appropriate portion of new data
701  */
702  n = LOBLKSIZE - off;
703  n = (n <= (nbytes - nwritten)) ? n : (nbytes - nwritten);
704  memcpy(workb + off, buf + nwritten, n);
705  nwritten += n;
706  obj_desc->offset += n;
707  off += n;
708  /* compute valid length of new page */
709  len = (len >= off) ? len : off;
710  SET_VARSIZE(&workbuf.hdr, len + VARHDRSZ);
711 
712  /*
713  * Form and insert updated tuple
714  */
715  memset(values, 0, sizeof(values));
716  memset(nulls, false, sizeof(nulls));
717  memset(replace, false, sizeof(replace));
718  values[Anum_pg_largeobject_data - 1] = PointerGetDatum(&workbuf);
719  replace[Anum_pg_largeobject_data - 1] = true;
720  newtup = heap_modify_tuple(oldtuple, RelationGetDescr(lo_heap_r),
721  values, nulls, replace);
722  CatalogTupleUpdateWithInfo(lo_heap_r, &newtup->t_self, newtup,
723  indstate);
724  heap_freetuple(newtup);
725 
726  /*
727  * We're done with this old page.
728  */
729  oldtuple = NULL;
730  olddata = NULL;
731  neednextpage = true;
732  }
733  else
734  {
735  /*
736  * Write a brand new page.
737  *
738  * First, fill any hole
739  */
740  off = (int) (obj_desc->offset % LOBLKSIZE);
741  if (off > 0)
742  MemSet(workb, 0, off);
743 
744  /*
745  * Insert appropriate portion of new data
746  */
747  n = LOBLKSIZE - off;
748  n = (n <= (nbytes - nwritten)) ? n : (nbytes - nwritten);
749  memcpy(workb + off, buf + nwritten, n);
750  nwritten += n;
751  obj_desc->offset += n;
752  /* compute valid length of new page */
753  len = off + n;
754  SET_VARSIZE(&workbuf.hdr, len + VARHDRSZ);
755 
756  /*
757  * Form and insert updated tuple
758  */
759  memset(values, 0, sizeof(values));
760  memset(nulls, false, sizeof(nulls));
761  values[Anum_pg_largeobject_loid - 1] = ObjectIdGetDatum(obj_desc->id);
762  values[Anum_pg_largeobject_pageno - 1] = Int32GetDatum(pageno);
763  values[Anum_pg_largeobject_data - 1] = PointerGetDatum(&workbuf);
764  newtup = heap_form_tuple(lo_heap_r->rd_att, values, nulls);
765  CatalogTupleInsertWithInfo(lo_heap_r, newtup, indstate);
766  heap_freetuple(newtup);
767  }
768  pageno++;
769  }
770 
772 
773  CatalogCloseIndexes(indstate);
774 
775  /*
776  * Advance command counter so that my tuple updates will be seen by later
777  * large-object operations in this transaction.
778  */
780 
781  return nwritten;
782 }
#define MAX_LARGE_OBJECT_SIZE
Definition: large_object.h:76
static void open_lo_relation(void)
Definition: inv_api.c:75
#define LOBLKSIZE
Definition: large_object.h:70
#define VARDATA(PTR)
Definition: postgres.h:302
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
#define RelationGetDescr(relation)
Definition: rel.h:482
#define PointerGetDatum(X)
Definition: postgres.h:556
#define VARHDRSZ
Definition: c.h:568
int errcode(int sqlerrcode)
Definition: elog.c:610
#define MemSet(start, val, len)
Definition: c.h:949
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
HeapTuple systable_getnext_ordered(SysScanDesc sysscan, ScanDirection direction)
Definition: genam.c:681
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
static Relation lo_heap_r
Definition: inv_api.c:67
#define IFS_WRLOCK
Definition: large_object.h:49
signed int int32
Definition: c.h:362
static Relation lo_index_r
Definition: inv_api.c:68
void pfree(void *pointer)
Definition: mcxt.c:1057
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
Snapshot snapshot
Definition: large_object.h:42
ItemPointerData t_self
Definition: htup.h:65
#define HeapTupleHasNulls(tuple)
Definition: htup_details.h:661
static char * buf
Definition: pg_test_fsync.c:68
void CatalogTupleUpdateWithInfo(Relation heapRel, ItemPointer otid, HeapTuple tup, CatalogIndexState indstate)
Definition: indexing.c:324
uintptr_t Datum
Definition: postgres.h:367
void CommandCounterIncrement(void)
Definition: xact.c:1021
void CatalogTupleInsertWithInfo(Relation heapRel, HeapTuple tup, CatalogIndexState indstate)
Definition: indexing.c:244
void systable_endscan_ordered(SysScanDesc sysscan)
Definition: genam.c:706
TupleDesc rd_att
Definition: rel.h:110
#define ereport(elevel,...)
Definition: elog.h:144
#define Assert(condition)
Definition: c.h:745
static void getdatafield(Form_pg_largeobject tuple, bytea **pdatafield, int *plen, bool *pfreeit)
Definition: inv_api.c:170
CatalogIndexState CatalogOpenIndexes(Relation heapRel)
Definition: indexing.c:43
static Datum values[MAXATTR]
Definition: bootstrap.c:165
#define Int32GetDatum(X)
Definition: postgres.h:479
int errmsg(const char *fmt,...)
Definition: elog.c:824
SysScanDesc systable_beginscan_ordered(Relation heapRelation, Relation indexRelation, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:616
#define elog(elevel,...)
Definition: elog.h:214
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
void CatalogCloseIndexes(CatalogIndexState indstate)
Definition: indexing.c:61
Definition: c.h:562
#define SET_VARSIZE(PTR, len)
Definition: postgres.h:329
FormData_pg_largeobject * Form_pg_largeobject
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:1113
#define PointerIsValid(pointer)
Definition: c.h:639
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define BTGreaterEqualStrategyNumber
Definition: stratnum.h:32

◆ myLargeObjectExists()

static bool myLargeObjectExists ( Oid  loid,
Snapshot  snapshot 
)
static

Definition at line 132 of file inv_api.c.

References AccessShareLock, BTEqualStrategyNumber, HeapTupleIsValid, LargeObjectMetadataOidIndexId, ObjectIdGetDatum, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), and table_open().

Referenced by inv_open().

133 {
134  Relation pg_lo_meta;
135  ScanKeyData skey[1];
136  SysScanDesc sd;
137  HeapTuple tuple;
138  bool retval = false;
139 
140  ScanKeyInit(&skey[0],
141  Anum_pg_largeobject_metadata_oid,
142  BTEqualStrategyNumber, F_OIDEQ,
143  ObjectIdGetDatum(loid));
144 
145  pg_lo_meta = table_open(LargeObjectMetadataRelationId,
147 
148  sd = systable_beginscan(pg_lo_meta,
150  snapshot, 1, skey);
151 
152  tuple = systable_getnext(sd);
153  if (HeapTupleIsValid(tuple))
154  retval = true;
155 
156  systable_endscan(sd);
157 
158  table_close(pg_lo_meta, AccessShareLock);
159 
160  return retval;
161 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:569
#define AccessShareLock
Definition: lockdefs.h:36
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:357
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:476
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define LargeObjectMetadataOidIndexId
Definition: indexing.h:198
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
#define BTEqualStrategyNumber
Definition: stratnum.h:31

◆ open_lo_relation()

static void open_lo_relation ( void  )
static

Definition at line 75 of file inv_api.c.

References CurrentResourceOwner, index_open(), LargeObjectLOidPNIndexId, RowExclusiveLock, table_open(), and TopTransactionResourceOwner.

Referenced by inv_getsize(), inv_read(), inv_truncate(), and inv_write().

76 {
77  ResourceOwner currentOwner;
78 
79  if (lo_heap_r && lo_index_r)
80  return; /* already open in current xact */
81 
82  /* Arrange for the top xact to own these relation references */
83  currentOwner = CurrentResourceOwner;
85 
86  /* Use RowExclusiveLock since we might either read or write */
87  if (lo_heap_r == NULL)
88  lo_heap_r = table_open(LargeObjectRelationId, RowExclusiveLock);
89  if (lo_index_r == NULL)
91 
92  CurrentResourceOwner = currentOwner;
93 }
ResourceOwner TopTransactionResourceOwner
Definition: resowner.c:144
ResourceOwner CurrentResourceOwner
Definition: resowner.c:142
static Relation lo_heap_r
Definition: inv_api.c:67
static Relation lo_index_r
Definition: inv_api.c:68
#define LargeObjectLOidPNIndexId
Definition: indexing.h:195
#define RowExclusiveLock
Definition: lockdefs.h:38
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:132

Variable Documentation

◆ lo_compat_privileges

bool lo_compat_privileges

Definition at line 58 of file inv_api.c.

Referenced by be_lo_put(), be_lo_unlink(), check_object_ownership(), and inv_open().

◆ lo_heap_r

Relation lo_heap_r = NULL
static

Definition at line 67 of file inv_api.c.

◆ lo_index_r

Relation lo_index_r = NULL
static

Definition at line 68 of file inv_api.c.