Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * pg_largeobject.c
4 : * routines to support manipulation of the pg_largeobject relation
5 : *
6 : * Portions Copyright (c) 1996-2024, 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/table.h"
20 : #include "catalog/catalog.h"
21 : #include "catalog/indexing.h"
22 : #include "catalog/pg_largeobject.h"
23 : #include "catalog/pg_largeobject_metadata.h"
24 : #include "miscadmin.h"
25 : #include "utils/fmgroids.h"
26 : #include "utils/rel.h"
27 :
28 :
29 : /*
30 : * Create a large object having the given LO identifier.
31 : *
32 : * We create a new large object by inserting an entry into
33 : * pg_largeobject_metadata without any data pages, so that the object
34 : * will appear to exist with size 0.
35 : */
36 : Oid
37 112 : LargeObjectCreate(Oid loid)
38 : {
39 : Relation pg_lo_meta;
40 : HeapTuple ntup;
41 : Oid loid_new;
42 : Datum values[Natts_pg_largeobject_metadata];
43 : bool nulls[Natts_pg_largeobject_metadata];
44 :
45 112 : pg_lo_meta = table_open(LargeObjectMetadataRelationId,
46 : RowExclusiveLock);
47 :
48 : /*
49 : * Insert metadata of the largeobject
50 : */
51 112 : memset(values, 0, sizeof(values));
52 112 : memset(nulls, false, sizeof(nulls));
53 :
54 112 : if (OidIsValid(loid))
55 64 : loid_new = loid;
56 : else
57 48 : loid_new = GetNewOidWithIndex(pg_lo_meta,
58 : LargeObjectMetadataOidIndexId,
59 : Anum_pg_largeobject_metadata_oid);
60 :
61 112 : values[Anum_pg_largeobject_metadata_oid - 1] = ObjectIdGetDatum(loid_new);
62 : values[Anum_pg_largeobject_metadata_lomowner - 1]
63 112 : = ObjectIdGetDatum(GetUserId());
64 112 : nulls[Anum_pg_largeobject_metadata_lomacl - 1] = true;
65 :
66 112 : ntup = heap_form_tuple(RelationGetDescr(pg_lo_meta),
67 : values, nulls);
68 :
69 112 : CatalogTupleInsert(pg_lo_meta, ntup);
70 :
71 112 : heap_freetuple(ntup);
72 :
73 112 : table_close(pg_lo_meta, RowExclusiveLock);
74 :
75 112 : 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
83 88 : 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 88 : pg_lo_meta = table_open(LargeObjectMetadataRelationId,
92 : RowExclusiveLock);
93 :
94 88 : pg_largeobject = table_open(LargeObjectRelationId,
95 : RowExclusiveLock);
96 :
97 : /*
98 : * Delete an entry from pg_largeobject_metadata
99 : */
100 88 : ScanKeyInit(&skey[0],
101 : Anum_pg_largeobject_metadata_oid,
102 : BTEqualStrategyNumber, F_OIDEQ,
103 : ObjectIdGetDatum(loid));
104 :
105 88 : scan = systable_beginscan(pg_lo_meta,
106 : LargeObjectMetadataOidIndexId, true,
107 : NULL, 1, skey);
108 :
109 88 : tuple = systable_getnext(scan);
110 88 : if (!HeapTupleIsValid(tuple))
111 0 : ereport(ERROR,
112 : (errcode(ERRCODE_UNDEFINED_OBJECT),
113 : errmsg("large object %u does not exist", loid)));
114 :
115 88 : CatalogTupleDelete(pg_lo_meta, &tuple->t_self);
116 :
117 88 : systable_endscan(scan);
118 :
119 : /*
120 : * Delete all the associated entries from pg_largeobject
121 : */
122 88 : ScanKeyInit(&skey[0],
123 : Anum_pg_largeobject_loid,
124 : BTEqualStrategyNumber, F_OIDEQ,
125 : ObjectIdGetDatum(loid));
126 :
127 88 : scan = systable_beginscan(pg_largeobject,
128 : LargeObjectLOidPNIndexId, true,
129 : NULL, 1, skey);
130 8014 : while (HeapTupleIsValid(tuple = systable_getnext(scan)))
131 : {
132 7926 : CatalogTupleDelete(pg_largeobject, &tuple->t_self);
133 : }
134 :
135 88 : systable_endscan(scan);
136 :
137 88 : table_close(pg_largeobject, RowExclusiveLock);
138 :
139 88 : table_close(pg_lo_meta, RowExclusiveLock);
140 88 : }
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
155 146 : LargeObjectExists(Oid loid)
156 : {
157 : Relation pg_lo_meta;
158 : ScanKeyData skey[1];
159 : SysScanDesc sd;
160 : HeapTuple tuple;
161 146 : bool retval = false;
162 :
163 146 : ScanKeyInit(&skey[0],
164 : Anum_pg_largeobject_metadata_oid,
165 : BTEqualStrategyNumber, F_OIDEQ,
166 : ObjectIdGetDatum(loid));
167 :
168 146 : pg_lo_meta = table_open(LargeObjectMetadataRelationId,
169 : AccessShareLock);
170 :
171 146 : sd = systable_beginscan(pg_lo_meta,
172 : LargeObjectMetadataOidIndexId, true,
173 : NULL, 1, skey);
174 :
175 146 : tuple = systable_getnext(sd);
176 146 : if (HeapTupleIsValid(tuple))
177 110 : retval = true;
178 :
179 146 : systable_endscan(sd);
180 :
181 146 : table_close(pg_lo_meta, AccessShareLock);
182 :
183 146 : return retval;
184 : }
|