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