1 /*-------------------------------------------------------------------------
2  *
3  * pg_largeobject.c
4  *	  routines to support manipulation of the pg_largeobject relation
5  *
6  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *	  src/backend/catalog/pg_largeobject.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16 
17 #include "access/genam.h"
18 #include "access/heapam.h"
19 #include "access/htup_details.h"
20 #include "access/sysattr.h"
21 #include "catalog/dependency.h"
22 #include "catalog/indexing.h"
23 #include "catalog/pg_largeobject.h"
24 #include "catalog/pg_largeobject_metadata.h"
25 #include "miscadmin.h"
26 #include "utils/acl.h"
27 #include "utils/fmgroids.h"
28 #include "utils/rel.h"
29 #include "utils/tqual.h"
30 
31 
32 /*
33  * Create a large object having the given LO identifier.
34  *
35  * We create a new large object by inserting an entry into
36  * pg_largeobject_metadata without any data pages, so that the object
37  * will appear to exist with size 0.
38  */
39 Oid
LargeObjectCreate(Oid loid)40 LargeObjectCreate(Oid loid)
41 {
42 	Relation	pg_lo_meta;
43 	HeapTuple	ntup;
44 	Oid			loid_new;
45 	Datum		values[Natts_pg_largeobject_metadata];
46 	bool		nulls[Natts_pg_largeobject_metadata];
47 
48 	pg_lo_meta = heap_open(LargeObjectMetadataRelationId,
49 						   RowExclusiveLock);
50 
51 	/*
52 	 * Insert metadata of the largeobject
53 	 */
54 	memset(values, 0, sizeof(values));
55 	memset(nulls, false, sizeof(nulls));
56 
57 	values[Anum_pg_largeobject_metadata_lomowner - 1]
58 		= ObjectIdGetDatum(GetUserId());
59 	nulls[Anum_pg_largeobject_metadata_lomacl - 1] = true;
60 
61 	ntup = heap_form_tuple(RelationGetDescr(pg_lo_meta),
62 						   values, nulls);
63 	if (OidIsValid(loid))
64 		HeapTupleSetOid(ntup, loid);
65 
66 	loid_new = CatalogTupleInsert(pg_lo_meta, ntup);
67 	Assert(!OidIsValid(loid) || loid == loid_new);
68 
69 	heap_freetuple(ntup);
70 
71 	heap_close(pg_lo_meta, RowExclusiveLock);
72 
73 	return loid_new;
74 }
75 
76 /*
77  * Drop a large object having the given LO identifier.  Both the data pages
78  * and metadata must be dropped.
79  */
80 void
LargeObjectDrop(Oid loid)81 LargeObjectDrop(Oid loid)
82 {
83 	Relation	pg_lo_meta;
84 	Relation	pg_largeobject;
85 	ScanKeyData skey[1];
86 	SysScanDesc scan;
87 	HeapTuple	tuple;
88 
89 	pg_lo_meta = heap_open(LargeObjectMetadataRelationId,
90 						   RowExclusiveLock);
91 
92 	pg_largeobject = heap_open(LargeObjectRelationId,
93 							   RowExclusiveLock);
94 
95 	/*
96 	 * Delete an entry from pg_largeobject_metadata
97 	 */
98 	ScanKeyInit(&skey[0],
99 				ObjectIdAttributeNumber,
100 				BTEqualStrategyNumber, F_OIDEQ,
101 				ObjectIdGetDatum(loid));
102 
103 	scan = systable_beginscan(pg_lo_meta,
104 							  LargeObjectMetadataOidIndexId, true,
105 							  NULL, 1, skey);
106 
107 	tuple = systable_getnext(scan);
108 	if (!HeapTupleIsValid(tuple))
109 		ereport(ERROR,
110 				(errcode(ERRCODE_UNDEFINED_OBJECT),
111 				 errmsg("large object %u does not exist", loid)));
112 
113 	CatalogTupleDelete(pg_lo_meta, &tuple->t_self);
114 
115 	systable_endscan(scan);
116 
117 	/*
118 	 * Delete all the associated entries from pg_largeobject
119 	 */
120 	ScanKeyInit(&skey[0],
121 				Anum_pg_largeobject_loid,
122 				BTEqualStrategyNumber, F_OIDEQ,
123 				ObjectIdGetDatum(loid));
124 
125 	scan = systable_beginscan(pg_largeobject,
126 							  LargeObjectLOidPNIndexId, true,
127 							  NULL, 1, skey);
128 	while (HeapTupleIsValid(tuple = systable_getnext(scan)))
129 	{
130 		CatalogTupleDelete(pg_largeobject, &tuple->t_self);
131 	}
132 
133 	systable_endscan(scan);
134 
135 	heap_close(pg_largeobject, RowExclusiveLock);
136 
137 	heap_close(pg_lo_meta, RowExclusiveLock);
138 }
139 
140 /*
141  * LargeObjectExists
142  *
143  * We don't use the system cache for large object metadata, for fear of
144  * using too much local memory.
145  *
146  * This function always scans the system catalog using an up-to-date snapshot,
147  * so it should not be used when a large object is opened in read-only mode
148  * (because large objects opened in read only mode are supposed to be viewed
149  * relative to the caller's snapshot, whereas in read-write mode they are
150  * relative to a current snapshot).
151  */
152 bool
LargeObjectExists(Oid loid)153 LargeObjectExists(Oid loid)
154 {
155 	Relation	pg_lo_meta;
156 	ScanKeyData skey[1];
157 	SysScanDesc sd;
158 	HeapTuple	tuple;
159 	bool		retval = false;
160 
161 	ScanKeyInit(&skey[0],
162 				ObjectIdAttributeNumber,
163 				BTEqualStrategyNumber, F_OIDEQ,
164 				ObjectIdGetDatum(loid));
165 
166 	pg_lo_meta = heap_open(LargeObjectMetadataRelationId,
167 						   AccessShareLock);
168 
169 	sd = systable_beginscan(pg_lo_meta,
170 							LargeObjectMetadataOidIndexId, true,
171 							NULL, 1, skey);
172 
173 	tuple = systable_getnext(sd);
174 	if (HeapTupleIsValid(tuple))
175 		retval = true;
176 
177 	systable_endscan(sd);
178 
179 	heap_close(pg_lo_meta, AccessShareLock);
180 
181 	return retval;
182 }
183