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