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