1 /*-------------------------------------------------------------------------
2  *
3  * pg_largeobject.c
4  *	  routines to support manipulation of the pg_largeobject relation
5  *
6  * Portions Copyright (c) 1996-2016, 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 = simple_heap_insert(pg_lo_meta, ntup);
67 	Assert(!OidIsValid(loid) || loid == loid_new);
68 
69 	CatalogUpdateIndexes(pg_lo_meta, ntup);
70 
71 	heap_freetuple(ntup);
72 
73 	heap_close(pg_lo_meta, RowExclusiveLock);
74 
75 	return loid_new;
76 }
77 
78 /*
79  * Drop a large object having the given LO identifier.  Both the data pages
80  * and metadata must be dropped.
81  */
82 void
LargeObjectDrop(Oid loid)83 LargeObjectDrop(Oid loid)
84 {
85 	Relation	pg_lo_meta;
86 	Relation	pg_largeobject;
87 	ScanKeyData skey[1];
88 	SysScanDesc scan;
89 	HeapTuple	tuple;
90 
91 	pg_lo_meta = heap_open(LargeObjectMetadataRelationId,
92 						   RowExclusiveLock);
93 
94 	pg_largeobject = heap_open(LargeObjectRelationId,
95 							   RowExclusiveLock);
96 
97 	/*
98 	 * Delete an entry from pg_largeobject_metadata
99 	 */
100 	ScanKeyInit(&skey[0],
101 				ObjectIdAttributeNumber,
102 				BTEqualStrategyNumber, F_OIDEQ,
103 				ObjectIdGetDatum(loid));
104 
105 	scan = systable_beginscan(pg_lo_meta,
106 							  LargeObjectMetadataOidIndexId, true,
107 							  NULL, 1, skey);
108 
109 	tuple = systable_getnext(scan);
110 	if (!HeapTupleIsValid(tuple))
111 		ereport(ERROR,
112 				(errcode(ERRCODE_UNDEFINED_OBJECT),
113 				 errmsg("large object %u does not exist", loid)));
114 
115 	simple_heap_delete(pg_lo_meta, &tuple->t_self);
116 
117 	systable_endscan(scan);
118 
119 	/*
120 	 * Delete all the associated entries from pg_largeobject
121 	 */
122 	ScanKeyInit(&skey[0],
123 				Anum_pg_largeobject_loid,
124 				BTEqualStrategyNumber, F_OIDEQ,
125 				ObjectIdGetDatum(loid));
126 
127 	scan = systable_beginscan(pg_largeobject,
128 							  LargeObjectLOidPNIndexId, true,
129 							  NULL, 1, skey);
130 	while (HeapTupleIsValid(tuple = systable_getnext(scan)))
131 	{
132 		simple_heap_delete(pg_largeobject, &tuple->t_self);
133 	}
134 
135 	systable_endscan(scan);
136 
137 	heap_close(pg_largeobject, RowExclusiveLock);
138 
139 	heap_close(pg_lo_meta, RowExclusiveLock);
140 }
141 
142 /*
143  * LargeObjectExists
144  *
145  * We don't use the system cache for large object metadata, for fear of
146  * using too much local memory.
147  *
148  * This function always scans the system catalog using an up-to-date snapshot,
149  * so it should not be used when a large object is opened in read-only mode
150  * (because large objects opened in read only mode are supposed to be viewed
151  * relative to the caller's snapshot, whereas in read-write mode they are
152  * relative to a current snapshot).
153  */
154 bool
LargeObjectExists(Oid loid)155 LargeObjectExists(Oid loid)
156 {
157 	Relation	pg_lo_meta;
158 	ScanKeyData skey[1];
159 	SysScanDesc sd;
160 	HeapTuple	tuple;
161 	bool		retval = false;
162 
163 	ScanKeyInit(&skey[0],
164 				ObjectIdAttributeNumber,
165 				BTEqualStrategyNumber, F_OIDEQ,
166 				ObjectIdGetDatum(loid));
167 
168 	pg_lo_meta = heap_open(LargeObjectMetadataRelationId,
169 						   AccessShareLock);
170 
171 	sd = systable_beginscan(pg_lo_meta,
172 							LargeObjectMetadataOidIndexId, true,
173 							NULL, 1, skey);
174 
175 	tuple = systable_getnext(sd);
176 	if (HeapTupleIsValid(tuple))
177 		retval = true;
178 
179 	systable_endscan(sd);
180 
181 	heap_close(pg_lo_meta, AccessShareLock);
182 
183 	return retval;
184 }
185