PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
large_object.h File Reference
#include "utils/snapshot.h"
Include dependency graph for large_object.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  LargeObjectDesc
 

Macros

#define IFS_RDLOCK   (1 << 0) /* LO was opened for reading */
 
#define IFS_WRLOCK   (1 << 1) /* LO was opened for writing */
 
#define IFS_RD_PERM_OK   (1 << 2) /* read permission has been verified */
 
#define IFS_WR_PERM_OK   (1 << 3) /* write permission has been verified */
 
#define LOBLKSIZE   (BLCKSZ / 4)
 
#define MAX_LARGE_OBJECT_SIZE   ((int64) INT_MAX * LOBLKSIZE)
 

Typedefs

typedef struct LargeObjectDesc LargeObjectDesc
 

Functions

void close_lo_relation (bool isCommit)
 
Oid inv_create (Oid lobjId)
 
LargeObjectDescinv_open (Oid lobjId, int flags, MemoryContext mcxt)
 
void inv_close (LargeObjectDesc *obj_desc)
 
int inv_drop (Oid lobjId)
 
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)
 

Macro Definition Documentation

#define IFS_RD_PERM_OK   (1 << 2) /* read permission has been verified */

Definition at line 50 of file large_object.h.

Referenced by lo_read().

#define IFS_RDLOCK   (1 << 0) /* LO was opened for reading */

Definition at line 48 of file large_object.h.

Referenced by inv_open().

#define IFS_WR_PERM_OK   (1 << 3) /* write permission has been verified */

Definition at line 51 of file large_object.h.

Referenced by lo_truncate_internal(), and lo_write().

#define IFS_WRLOCK   (1 << 1) /* LO was opened for writing */

Definition at line 49 of file large_object.h.

Referenced by inv_open(), inv_truncate(), inv_write(), lo_truncate_internal(), and lo_write().

#define LOBLKSIZE   (BLCKSZ / 4)
#define MAX_LARGE_OBJECT_SIZE   ((int64) INT_MAX * LOBLKSIZE)

Definition at line 78 of file large_object.h.

Referenced by inv_seek(), inv_truncate(), and inv_write().

Typedef Documentation

Function Documentation

void close_lo_relation ( bool  isCommit)

Definition at line 93 of file inv_api.c.

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

Referenced by AtEOXact_LargeObject().

94 {
95  if (lo_heap_r || lo_index_r)
96  {
97  /*
98  * Only bother to close if committing; else abort cleanup will handle
99  * it
100  */
101  if (isCommit)
102  {
103  ResourceOwner currentOwner;
104 
105  currentOwner = CurrentResourceOwner;
107 
108  if (lo_index_r)
110  if (lo_heap_r)
112 
113  CurrentResourceOwner = currentOwner;
114  }
115  lo_heap_r = NULL;
116  lo_index_r = NULL;
117  }
118 }
ResourceOwner TopTransactionResourceOwner
Definition: resowner.c:140
ResourceOwner CurrentResourceOwner
Definition: resowner.c:138
#define heap_close(r, l)
Definition: heapam.h:97
static Relation lo_heap_r
Definition: inv_api.c:61
static Relation lo_index_r
Definition: inv_api.c:62
#define NoLock
Definition: lockdefs.h:34
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:176
void inv_close ( LargeObjectDesc obj_desc)

Definition at line 302 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().

303 {
304  Assert(PointerIsValid(obj_desc));
305 
308 
309  pfree(obj_desc);
310 }
ResourceOwner TopTransactionResourceOwner
Definition: resowner.c:140
void pfree(void *pointer)
Definition: mcxt.c:949
Snapshot snapshot
Definition: large_object.h:42
#define Assert(condition)
Definition: c.h:681
void UnregisterSnapshotFromOwner(Snapshot snapshot, ResourceOwner owner)
Definition: snapmgr.c:918
#define PointerIsValid(pointer)
Definition: c.h:520
Oid inv_create ( Oid  lobjId)

Definition at line 206 of file inv_api.c.

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

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

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

Definition at line 318 of file inv_api.c.

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

Referenced by be_lo_unlink().

319 {
320  ObjectAddress object;
321 
322  /*
323  * Delete any comments and dependencies on the large object
324  */
326  object.objectId = lobjId;
327  object.objectSubId = 0;
328  performDeletion(&object, DROP_CASCADE, 0);
329 
330  /*
331  * Advance command counter so that tuple removal will be seen by later
332  * large-object operations in this transaction.
333  */
335 
336  return 1;
337 }
void performDeletion(const ObjectAddress *object, DropBehavior behavior, int flags)
Definition: dependency.c:303
void CommandCounterIncrement(void)
Definition: xact.c:915
#define LargeObjectRelationId
LargeObjectDesc* inv_open ( Oid  lobjId,
int  flags,
MemoryContext  mcxt 
)

Definition at line 247 of file inv_api.c.

References ereport, errcode(), errmsg(), ERROR, LargeObjectDesc::flags, GetActiveSnapshot(), GetCurrentSubTransactionId(), LargeObjectDesc::id, IFS_RDLOCK, IFS_WRLOCK, INV_READ, INV_WRITE, MemoryContextAlloc(), myLargeObjectExists(), LargeObjectDesc::offset, 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().

248 {
249  LargeObjectDesc *retval;
250  Snapshot snapshot = NULL;
251  int descflags = 0;
252 
253  if (flags & INV_WRITE)
254  {
255  snapshot = NULL; /* instantaneous MVCC snapshot */
256  descflags = IFS_WRLOCK | IFS_RDLOCK;
257  }
258  else if (flags & INV_READ)
259  {
260  snapshot = GetActiveSnapshot();
261  descflags = IFS_RDLOCK;
262  }
263  else
264  ereport(ERROR,
265  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
266  errmsg("invalid flags for opening a large object: %d",
267  flags)));
268 
269  /* Can't use LargeObjectExists here because we need to specify snapshot */
270  if (!myLargeObjectExists(lobjId, snapshot))
271  ereport(ERROR,
272  (errcode(ERRCODE_UNDEFINED_OBJECT),
273  errmsg("large object %u does not exist", lobjId)));
274 
275  /*
276  * We must register the snapshot in TopTransaction's resowner, because it
277  * must stay alive until the LO is closed rather than until the current
278  * portal shuts down. Do this after checking that the LO exists, to avoid
279  * leaking the snapshot if an error is thrown.
280  */
281  if (snapshot)
282  snapshot = RegisterSnapshotOnOwner(snapshot,
284 
285  /* All set, create a descriptor */
286  retval = (LargeObjectDesc *) MemoryContextAlloc(mcxt,
287  sizeof(LargeObjectDesc));
288  retval->id = lobjId;
289  retval->subid = GetCurrentSubTransactionId();
290  retval->offset = 0;
291  retval->snapshot = snapshot;
292  retval->flags = descflags;
293 
294  return retval;
295 }
static bool myLargeObjectExists(Oid loid, Snapshot snapshot)
Definition: inv_api.c:126
#define IFS_RDLOCK
Definition: large_object.h:48
ResourceOwner TopTransactionResourceOwner
Definition: resowner.c:140
Snapshot GetActiveSnapshot(void)
Definition: snapmgr.c:839
int errcode(int sqlerrcode)
Definition: elog.c:575
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 ereport(elevel, rest)
Definition: elog.h:122
Snapshot RegisterSnapshotOnOwner(Snapshot snapshot, ResourceOwner owner)
Definition: snapmgr.c:876
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:642
#define INV_WRITE
Definition: libpq-fs.h:21
int errmsg(const char *fmt,...)
Definition: elog.c:797
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:706
int inv_read ( LargeObjectDesc obj_desc,
char *  buf,
int  nbytes 
)

Definition at line 446 of file inv_api.c.

References Anum_pg_largeobject_loid, Anum_pg_largeobject_pageno, Assert, BTEqualStrategyNumber, BTGreaterEqualStrategyNumber, elog, ERROR, ForwardScanDirection, getdatafield(), GETSTRUCT, HeapTupleHasNulls, LargeObjectDesc::id, 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().

447 {
448  int nread = 0;
449  int64 n;
450  int64 off;
451  int len;
452  int32 pageno = (int32) (obj_desc->offset / LOBLKSIZE);
453  uint64 pageoff;
454  ScanKeyData skey[2];
455  SysScanDesc sd;
456  HeapTuple tuple;
457 
458  Assert(PointerIsValid(obj_desc));
459  Assert(buf != NULL);
460 
461  if (nbytes <= 0)
462  return 0;
463 
465 
466  ScanKeyInit(&skey[0],
468  BTEqualStrategyNumber, F_OIDEQ,
469  ObjectIdGetDatum(obj_desc->id));
470 
471  ScanKeyInit(&skey[1],
474  Int32GetDatum(pageno));
475 
477  obj_desc->snapshot, 2, skey);
478 
479  while ((tuple = systable_getnext_ordered(sd, ForwardScanDirection)) != NULL)
480  {
481  Form_pg_largeobject data;
482  bytea *datafield;
483  bool pfreeit;
484 
485  if (HeapTupleHasNulls(tuple)) /* paranoia */
486  elog(ERROR, "null field found in pg_largeobject");
487  data = (Form_pg_largeobject) GETSTRUCT(tuple);
488 
489  /*
490  * We expect the indexscan will deliver pages in order. However,
491  * there may be missing pages if the LO contains unwritten "holes". We
492  * want missing sections to read out as zeroes.
493  */
494  pageoff = ((uint64) data->pageno) * LOBLKSIZE;
495  if (pageoff > obj_desc->offset)
496  {
497  n = pageoff - obj_desc->offset;
498  n = (n <= (nbytes - nread)) ? n : (nbytes - nread);
499  MemSet(buf + nread, 0, n);
500  nread += n;
501  obj_desc->offset += n;
502  }
503 
504  if (nread < nbytes)
505  {
506  Assert(obj_desc->offset >= pageoff);
507  off = (int) (obj_desc->offset - pageoff);
508  Assert(off >= 0 && off < LOBLKSIZE);
509 
510  getdatafield(data, &datafield, &len, &pfreeit);
511  if (len > off)
512  {
513  n = len - off;
514  n = (n <= (nbytes - nread)) ? n : (nbytes - nread);
515  memcpy(buf + nread, VARDATA(datafield) + off, n);
516  nread += n;
517  obj_desc->offset += n;
518  }
519  if (pfreeit)
520  pfree(datafield);
521  }
522 
523  if (nread >= nbytes)
524  break;
525  }
526 
528 
529  return nread;
530 }
static void open_lo_relation(void)
Definition: inv_api.c:69
#define LOBLKSIZE
Definition: large_object.h:72
#define VARDATA(PTR)
Definition: postgres.h:303
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
#define MemSet(start, val, len)
Definition: c.h:863
HeapTuple systable_getnext_ordered(SysScanDesc sysscan, ScanDirection direction)
Definition: genam.c:597
static Relation lo_heap_r
Definition: inv_api.c:61
signed int int32
Definition: c.h:246
static Relation lo_index_r
Definition: inv_api.c:62
void pfree(void *pointer)
Definition: mcxt.c:949
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
Snapshot snapshot
Definition: large_object.h:42
#define HeapTupleHasNulls(tuple)
Definition: htup_details.h:662
static char * buf
Definition: pg_test_fsync.c:67
void systable_endscan_ordered(SysScanDesc sysscan)
Definition: genam.c:614
#define Assert(condition)
Definition: c.h:681
static void getdatafield(Form_pg_largeobject tuple, bytea **pdatafield, int *plen, bool *pfreeit)
Definition: inv_api.c:164
#define Anum_pg_largeobject_pageno
#define Int32GetDatum(X)
Definition: postgres.h:485
SysScanDesc systable_beginscan_ordered(Relation heapRelation, Relation indexRelation, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:533
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
Definition: c.h:433
#define elog
Definition: elog.h:219
FormData_pg_largeobject * Form_pg_largeobject
#define Anum_pg_largeobject_loid
#define PointerIsValid(pointer)
Definition: c.h:520
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define BTGreaterEqualStrategyNumber
Definition: stratnum.h:32
int64 inv_seek ( LargeObjectDesc obj_desc,
int64  offset,
int  whence 
)

Definition at line 394 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().

395 {
396  int64 newoffset;
397 
398  Assert(PointerIsValid(obj_desc));
399 
400  /*
401  * Note: overflow in the additions is possible, but since we will reject
402  * negative results, we don't need any extra test for that.
403  */
404  switch (whence)
405  {
406  case SEEK_SET:
407  newoffset = offset;
408  break;
409  case SEEK_CUR:
410  newoffset = obj_desc->offset + offset;
411  break;
412  case SEEK_END:
413  newoffset = inv_getsize(obj_desc) + offset;
414  break;
415  default:
416  ereport(ERROR,
417  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
418  errmsg("invalid whence setting: %d", whence)));
419  newoffset = 0; /* keep compiler quiet */
420  break;
421  }
422 
423  /*
424  * use errmsg_internal here because we don't want to expose INT64_FORMAT
425  * in translatable strings; doing better is not worth the trouble
426  */
427  if (newoffset < 0 || newoffset > MAX_LARGE_OBJECT_SIZE)
428  ereport(ERROR,
429  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
430  errmsg_internal("invalid large object seek target: " INT64_FORMAT,
431  newoffset)));
432 
433  obj_desc->offset = newoffset;
434  return newoffset;
435 }
#define MAX_LARGE_OBJECT_SIZE
Definition: large_object.h:78
int errcode(int sqlerrcode)
Definition: elog.c:575
#define ERROR
Definition: elog.h:43
#define ereport(elevel, rest)
Definition: elog.h:122
static uint64 inv_getsize(LargeObjectDesc *obj_desc)
Definition: inv_api.c:346
int errmsg_internal(const char *fmt,...)
Definition: elog.c:827
#define Assert(condition)
Definition: c.h:681
#define INT64_FORMAT
Definition: c.h:300
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define PointerIsValid(pointer)
Definition: c.h:520
int64 inv_tell ( LargeObjectDesc obj_desc)

Definition at line 438 of file inv_api.c.

References Assert, LargeObjectDesc::offset, and PointerIsValid.

Referenced by be_lo_tell(), and be_lo_tell64().

439 {
440  Assert(PointerIsValid(obj_desc));
441 
442  return obj_desc->offset;
443 }
#define Assert(condition)
Definition: c.h:681
#define PointerIsValid(pointer)
Definition: c.h:520
void inv_truncate ( LargeObjectDesc obj_desc,
int64  len 
)

Definition at line 726 of file inv_api.c.

References Anum_pg_largeobject_data, Anum_pg_largeobject_loid, Anum_pg_largeobject_pageno, Assert, BTEqualStrategyNumber, BTGreaterEqualStrategyNumber, CatalogCloseIndexes(), CatalogOpenIndexes(), CatalogTupleDelete(), CatalogTupleInsertWithInfo(), CatalogTupleUpdateWithInfo(), CommandCounterIncrement(), elog, ereport, errcode(), 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, Natts_pg_largeobject, 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().

727 {
728  int32 pageno = (int32) (len / LOBLKSIZE);
729  int32 off;
730  ScanKeyData skey[2];
731  SysScanDesc sd;
732  HeapTuple oldtuple;
733  Form_pg_largeobject olddata;
734  union
735  {
736  bytea hdr;
737  /* this is to make the union big enough for a LO data chunk: */
738  char data[LOBLKSIZE + VARHDRSZ];
739  /* ensure union is aligned well enough: */
740  int32 align_it;
741  } workbuf;
742  char *workb = VARDATA(&workbuf.hdr);
743  HeapTuple newtup;
745  bool nulls[Natts_pg_largeobject];
746  bool replace[Natts_pg_largeobject];
747  CatalogIndexState indstate;
748 
749  Assert(PointerIsValid(obj_desc));
750 
751  /* enforce writability because snapshot is probably wrong otherwise */
752  Assert(obj_desc->flags & IFS_WRLOCK);
753 
754  /*
755  * use errmsg_internal here because we don't want to expose INT64_FORMAT
756  * in translatable strings; doing better is not worth the trouble
757  */
758  if (len < 0 || len > MAX_LARGE_OBJECT_SIZE)
759  ereport(ERROR,
760  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
761  errmsg_internal("invalid large object truncation target: " INT64_FORMAT,
762  len)));
763 
765 
766  indstate = CatalogOpenIndexes(lo_heap_r);
767 
768  /*
769  * Set up to find all pages with desired loid and pageno >= target
770  */
771  ScanKeyInit(&skey[0],
773  BTEqualStrategyNumber, F_OIDEQ,
774  ObjectIdGetDatum(obj_desc->id));
775 
776  ScanKeyInit(&skey[1],
779  Int32GetDatum(pageno));
780 
782  obj_desc->snapshot, 2, skey);
783 
784  /*
785  * If possible, get the page the truncation point is in. The truncation
786  * point may be beyond the end of the LO or in a hole.
787  */
788  olddata = NULL;
789  if ((oldtuple = systable_getnext_ordered(sd, ForwardScanDirection)) != NULL)
790  {
791  if (HeapTupleHasNulls(oldtuple)) /* paranoia */
792  elog(ERROR, "null field found in pg_largeobject");
793  olddata = (Form_pg_largeobject) GETSTRUCT(oldtuple);
794  Assert(olddata->pageno >= pageno);
795  }
796 
797  /*
798  * If we found the page of the truncation point we need to truncate the
799  * data in it. Otherwise if we're in a hole, we need to create a page to
800  * mark the end of data.
801  */
802  if (olddata != NULL && olddata->pageno == pageno)
803  {
804  /* First, load old data into workbuf */
805  bytea *datafield;
806  int pagelen;
807  bool pfreeit;
808 
809  getdatafield(olddata, &datafield, &pagelen, &pfreeit);
810  memcpy(workb, VARDATA(datafield), pagelen);
811  if (pfreeit)
812  pfree(datafield);
813 
814  /*
815  * Fill any hole
816  */
817  off = len % LOBLKSIZE;
818  if (off > pagelen)
819  MemSet(workb + pagelen, 0, off - pagelen);
820 
821  /* compute length of new page */
822  SET_VARSIZE(&workbuf.hdr, off + VARHDRSZ);
823 
824  /*
825  * Form and insert updated tuple
826  */
827  memset(values, 0, sizeof(values));
828  memset(nulls, false, sizeof(nulls));
829  memset(replace, false, sizeof(replace));
830  values[Anum_pg_largeobject_data - 1] = PointerGetDatum(&workbuf);
831  replace[Anum_pg_largeobject_data - 1] = true;
832  newtup = heap_modify_tuple(oldtuple, RelationGetDescr(lo_heap_r),
833  values, nulls, replace);
834  CatalogTupleUpdateWithInfo(lo_heap_r, &newtup->t_self, newtup,
835  indstate);
836  heap_freetuple(newtup);
837  }
838  else
839  {
840  /*
841  * If the first page we found was after the truncation point, we're in
842  * a hole that we'll fill, but we need to delete the later page
843  * because the loop below won't visit it again.
844  */
845  if (olddata != NULL)
846  {
847  Assert(olddata->pageno > pageno);
848  CatalogTupleDelete(lo_heap_r, &oldtuple->t_self);
849  }
850 
851  /*
852  * Write a brand new page.
853  *
854  * Fill the hole up to the truncation point
855  */
856  off = len % LOBLKSIZE;
857  if (off > 0)
858  MemSet(workb, 0, off);
859 
860  /* compute length of new page */
861  SET_VARSIZE(&workbuf.hdr, off + VARHDRSZ);
862 
863  /*
864  * Form and insert new tuple
865  */
866  memset(values, 0, sizeof(values));
867  memset(nulls, false, sizeof(nulls));
868  values[Anum_pg_largeobject_loid - 1] = ObjectIdGetDatum(obj_desc->id);
869  values[Anum_pg_largeobject_pageno - 1] = Int32GetDatum(pageno);
870  values[Anum_pg_largeobject_data - 1] = PointerGetDatum(&workbuf);
871  newtup = heap_form_tuple(lo_heap_r->rd_att, values, nulls);
872  CatalogTupleInsertWithInfo(lo_heap_r, newtup, indstate);
873  heap_freetuple(newtup);
874  }
875 
876  /*
877  * Delete any pages after the truncation point. If the initial search
878  * didn't find a page, then of course there's nothing more to do.
879  */
880  if (olddata != NULL)
881  {
882  while ((oldtuple = systable_getnext_ordered(sd, ForwardScanDirection)) != NULL)
883  {
884  CatalogTupleDelete(lo_heap_r, &oldtuple->t_self);
885  }
886  }
887 
889 
890  CatalogCloseIndexes(indstate);
891 
892  /*
893  * Advance command counter so that tuple updates will be seen by later
894  * large-object operations in this transaction.
895  */
897 }
#define MAX_LARGE_OBJECT_SIZE
Definition: large_object.h:78
static void open_lo_relation(void)
Definition: inv_api.c:69
#define LOBLKSIZE
Definition: large_object.h:72
#define VARDATA(PTR)
Definition: postgres.h:303
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
#define RelationGetDescr(relation)
Definition: rel.h:428
#define PointerGetDatum(X)
Definition: postgres.h:562
#define VARHDRSZ
Definition: c.h:439
int errcode(int sqlerrcode)
Definition: elog.c:575
#define MemSet(start, val, len)
Definition: c.h:863
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:255
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:695
HeapTuple systable_getnext_ordered(SysScanDesc sysscan, ScanDirection direction)
Definition: genam.c:597
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1373
static Relation lo_heap_r
Definition: inv_api.c:61
#define IFS_WRLOCK
Definition: large_object.h:49
signed int int32
Definition: c.h:246
static Relation lo_index_r
Definition: inv_api.c:62
void pfree(void *pointer)
Definition: mcxt.c:949
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#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:662
#define ereport(elevel, rest)
Definition: elog.h:122
void CatalogTupleUpdateWithInfo(Relation heapRel, ItemPointer otid, HeapTuple tup, CatalogIndexState indstate)
Definition: indexing.c:231
#define Natts_pg_largeobject
uintptr_t Datum
Definition: postgres.h:372
void CommandCounterIncrement(void)
Definition: xact.c:915
void systable_endscan_ordered(SysScanDesc sysscan)
Definition: genam.c:614
TupleDesc rd_att
Definition: rel.h:115
int errmsg_internal(const char *fmt,...)
Definition: elog.c:827
#define Assert(condition)
Definition: c.h:681
static void getdatafield(Form_pg_largeobject tuple, bytea **pdatafield, int *plen, bool *pfreeit)
Definition: inv_api.c:164
CatalogIndexState CatalogOpenIndexes(Relation heapRel)
Definition: indexing.c:40
#define Anum_pg_largeobject_data
#define INT64_FORMAT
Definition: c.h:300
#define Anum_pg_largeobject_pageno
static Datum values[MAXATTR]
Definition: bootstrap.c:164
#define Int32GetDatum(X)
Definition: postgres.h:485
SysScanDesc systable_beginscan_ordered(Relation heapRelation, Relation indexRelation, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:533
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
void CatalogCloseIndexes(CatalogIndexState indstate)
Definition: indexing.c:58
Definition: c.h:433
#define SET_VARSIZE(PTR, len)
Definition: postgres.h:328
#define elog
Definition: elog.h:219
Oid CatalogTupleInsertWithInfo(Relation heapRel, HeapTuple tup, CatalogIndexState indstate)
Definition: indexing.c:186
FormData_pg_largeobject * Form_pg_largeobject
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:794
#define Anum_pg_largeobject_loid
#define PointerIsValid(pointer)
Definition: c.h:520
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define BTGreaterEqualStrategyNumber
Definition: stratnum.h:32
int inv_write ( LargeObjectDesc obj_desc,
const char *  buf,
int  nbytes 
)

Definition at line 533 of file inv_api.c.

References Anum_pg_largeobject_data, Anum_pg_largeobject_loid, Anum_pg_largeobject_pageno, 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, Natts_pg_largeobject, 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().

534 {
535  int nwritten = 0;
536  int n;
537  int off;
538  int len;
539  int32 pageno = (int32) (obj_desc->offset / LOBLKSIZE);
540  ScanKeyData skey[2];
541  SysScanDesc sd;
542  HeapTuple oldtuple;
543  Form_pg_largeobject olddata;
544  bool neednextpage;
545  bytea *datafield;
546  bool pfreeit;
547  union
548  {
549  bytea hdr;
550  /* this is to make the union big enough for a LO data chunk: */
551  char data[LOBLKSIZE + VARHDRSZ];
552  /* ensure union is aligned well enough: */
553  int32 align_it;
554  } workbuf;
555  char *workb = VARDATA(&workbuf.hdr);
556  HeapTuple newtup;
558  bool nulls[Natts_pg_largeobject];
559  bool replace[Natts_pg_largeobject];
560  CatalogIndexState indstate;
561 
562  Assert(PointerIsValid(obj_desc));
563  Assert(buf != NULL);
564 
565  /* enforce writability because snapshot is probably wrong otherwise */
566  Assert(obj_desc->flags & IFS_WRLOCK);
567 
568  if (nbytes <= 0)
569  return 0;
570 
571  /* this addition can't overflow because nbytes is only int32 */
572  if ((nbytes + obj_desc->offset) > MAX_LARGE_OBJECT_SIZE)
573  ereport(ERROR,
574  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
575  errmsg("invalid large object write request size: %d",
576  nbytes)));
577 
579 
580  indstate = CatalogOpenIndexes(lo_heap_r);
581 
582  ScanKeyInit(&skey[0],
584  BTEqualStrategyNumber, F_OIDEQ,
585  ObjectIdGetDatum(obj_desc->id));
586 
587  ScanKeyInit(&skey[1],
590  Int32GetDatum(pageno));
591 
593  obj_desc->snapshot, 2, skey);
594 
595  oldtuple = NULL;
596  olddata = NULL;
597  neednextpage = true;
598 
599  while (nwritten < nbytes)
600  {
601  /*
602  * If possible, get next pre-existing page of the LO. We expect the
603  * indexscan will deliver these in order --- but there may be holes.
604  */
605  if (neednextpage)
606  {
607  if ((oldtuple = systable_getnext_ordered(sd, ForwardScanDirection)) != NULL)
608  {
609  if (HeapTupleHasNulls(oldtuple)) /* paranoia */
610  elog(ERROR, "null field found in pg_largeobject");
611  olddata = (Form_pg_largeobject) GETSTRUCT(oldtuple);
612  Assert(olddata->pageno >= pageno);
613  }
614  neednextpage = false;
615  }
616 
617  /*
618  * If we have a pre-existing page, see if it is the page we want to
619  * write, or a later one.
620  */
621  if (olddata != NULL && olddata->pageno == pageno)
622  {
623  /*
624  * Update an existing page with fresh data.
625  *
626  * First, load old data into workbuf
627  */
628  getdatafield(olddata, &datafield, &len, &pfreeit);
629  memcpy(workb, VARDATA(datafield), len);
630  if (pfreeit)
631  pfree(datafield);
632 
633  /*
634  * Fill any hole
635  */
636  off = (int) (obj_desc->offset % LOBLKSIZE);
637  if (off > len)
638  MemSet(workb + len, 0, off - len);
639 
640  /*
641  * Insert appropriate portion of new data
642  */
643  n = LOBLKSIZE - off;
644  n = (n <= (nbytes - nwritten)) ? n : (nbytes - nwritten);
645  memcpy(workb + off, buf + nwritten, n);
646  nwritten += n;
647  obj_desc->offset += n;
648  off += n;
649  /* compute valid length of new page */
650  len = (len >= off) ? len : off;
651  SET_VARSIZE(&workbuf.hdr, len + VARHDRSZ);
652 
653  /*
654  * Form and insert updated tuple
655  */
656  memset(values, 0, sizeof(values));
657  memset(nulls, false, sizeof(nulls));
658  memset(replace, false, sizeof(replace));
659  values[Anum_pg_largeobject_data - 1] = PointerGetDatum(&workbuf);
660  replace[Anum_pg_largeobject_data - 1] = true;
661  newtup = heap_modify_tuple(oldtuple, RelationGetDescr(lo_heap_r),
662  values, nulls, replace);
663  CatalogTupleUpdateWithInfo(lo_heap_r, &newtup->t_self, newtup,
664  indstate);
665  heap_freetuple(newtup);
666 
667  /*
668  * We're done with this old page.
669  */
670  oldtuple = NULL;
671  olddata = NULL;
672  neednextpage = true;
673  }
674  else
675  {
676  /*
677  * Write a brand new page.
678  *
679  * First, fill any hole
680  */
681  off = (int) (obj_desc->offset % LOBLKSIZE);
682  if (off > 0)
683  MemSet(workb, 0, off);
684 
685  /*
686  * Insert appropriate portion of new data
687  */
688  n = LOBLKSIZE - off;
689  n = (n <= (nbytes - nwritten)) ? n : (nbytes - nwritten);
690  memcpy(workb + off, buf + nwritten, n);
691  nwritten += n;
692  obj_desc->offset += n;
693  /* compute valid length of new page */
694  len = off + n;
695  SET_VARSIZE(&workbuf.hdr, len + VARHDRSZ);
696 
697  /*
698  * Form and insert updated tuple
699  */
700  memset(values, 0, sizeof(values));
701  memset(nulls, false, sizeof(nulls));
702  values[Anum_pg_largeobject_loid - 1] = ObjectIdGetDatum(obj_desc->id);
703  values[Anum_pg_largeobject_pageno - 1] = Int32GetDatum(pageno);
704  values[Anum_pg_largeobject_data - 1] = PointerGetDatum(&workbuf);
705  newtup = heap_form_tuple(lo_heap_r->rd_att, values, nulls);
706  CatalogTupleInsertWithInfo(lo_heap_r, newtup, indstate);
707  heap_freetuple(newtup);
708  }
709  pageno++;
710  }
711 
713 
714  CatalogCloseIndexes(indstate);
715 
716  /*
717  * Advance command counter so that my tuple updates will be seen by later
718  * large-object operations in this transaction.
719  */
721 
722  return nwritten;
723 }
#define MAX_LARGE_OBJECT_SIZE
Definition: large_object.h:78
static void open_lo_relation(void)
Definition: inv_api.c:69
#define LOBLKSIZE
Definition: large_object.h:72
#define VARDATA(PTR)
Definition: postgres.h:303
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
#define RelationGetDescr(relation)
Definition: rel.h:428
#define PointerGetDatum(X)
Definition: postgres.h:562
#define VARHDRSZ
Definition: c.h:439
int errcode(int sqlerrcode)
Definition: elog.c:575
#define MemSet(start, val, len)
Definition: c.h:863
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:695
HeapTuple systable_getnext_ordered(SysScanDesc sysscan, ScanDirection direction)
Definition: genam.c:597
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1373
static Relation lo_heap_r
Definition: inv_api.c:61
#define IFS_WRLOCK
Definition: large_object.h:49
signed int int32
Definition: c.h:246
static Relation lo_index_r
Definition: inv_api.c:62
void pfree(void *pointer)
Definition: mcxt.c:949
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#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:662
static char * buf
Definition: pg_test_fsync.c:67
#define ereport(elevel, rest)
Definition: elog.h:122
void CatalogTupleUpdateWithInfo(Relation heapRel, ItemPointer otid, HeapTuple tup, CatalogIndexState indstate)
Definition: indexing.c:231
#define Natts_pg_largeobject
uintptr_t Datum
Definition: postgres.h:372
void CommandCounterIncrement(void)
Definition: xact.c:915
void systable_endscan_ordered(SysScanDesc sysscan)
Definition: genam.c:614
TupleDesc rd_att
Definition: rel.h:115
#define Assert(condition)
Definition: c.h:681
static void getdatafield(Form_pg_largeobject tuple, bytea **pdatafield, int *plen, bool *pfreeit)
Definition: inv_api.c:164
CatalogIndexState CatalogOpenIndexes(Relation heapRel)
Definition: indexing.c:40
#define Anum_pg_largeobject_data
#define Anum_pg_largeobject_pageno
static Datum values[MAXATTR]
Definition: bootstrap.c:164
#define Int32GetDatum(X)
Definition: postgres.h:485
int errmsg(const char *fmt,...)
Definition: elog.c:797
SysScanDesc systable_beginscan_ordered(Relation heapRelation, Relation indexRelation, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:533
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
void CatalogCloseIndexes(CatalogIndexState indstate)
Definition: indexing.c:58
Definition: c.h:433
#define SET_VARSIZE(PTR, len)
Definition: postgres.h:328
#define elog
Definition: elog.h:219
Oid CatalogTupleInsertWithInfo(Relation heapRel, HeapTuple tup, CatalogIndexState indstate)
Definition: indexing.c:186
FormData_pg_largeobject * Form_pg_largeobject
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:794
#define Anum_pg_largeobject_loid
#define PointerIsValid(pointer)
Definition: c.h:520
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define BTGreaterEqualStrategyNumber
Definition: stratnum.h:32