Age Owner TLA 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-2023, 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 : */
39 : Oid
8202 tgl 40 CBC 56 : 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 :
1539 andres 48 56 : pg_lo_meta = table_open(LargeObjectMetadataRelationId,
49 : RowExclusiveLock);
50 :
51 : /*
52 : * Insert metadata of the largeobject
53 : */
4867 itagaki.takahiro 54 56 : memset(values, 0, sizeof(values));
55 56 : memset(nulls, false, sizeof(nulls));
56 :
1601 andres 57 56 : if (OidIsValid(loid))
58 32 : loid_new = loid;
59 : else
60 24 : loid_new = GetNewOidWithIndex(pg_lo_meta,
61 : LargeObjectMetadataOidIndexId,
62 : Anum_pg_largeobject_metadata_oid);
63 :
64 56 : values[Anum_pg_largeobject_metadata_oid - 1] = ObjectIdGetDatum(loid_new);
65 : values[Anum_pg_largeobject_metadata_lomowner - 1]
4867 itagaki.takahiro 66 56 : = ObjectIdGetDatum(GetUserId());
67 56 : nulls[Anum_pg_largeobject_metadata_lomacl - 1] = true;
68 :
69 56 : ntup = heap_form_tuple(RelationGetDescr(pg_lo_meta),
70 : values, nulls);
71 :
1601 andres 72 56 : CatalogTupleInsert(pg_lo_meta, ntup);
73 :
8202 tgl 74 56 : heap_freetuple(ntup);
75 :
1539 andres 76 56 : table_close(pg_lo_meta, RowExclusiveLock);
77 :
4867 itagaki.takahiro 78 56 : 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 : */
85 : void
8202 tgl 86 44 : LargeObjectDrop(Oid loid)
87 : {
88 : Relation pg_lo_meta;
89 : Relation pg_largeobject;
90 : ScanKeyData skey[1];
91 : SysScanDesc scan;
92 : HeapTuple tuple;
93 :
1539 andres 94 44 : pg_lo_meta = table_open(LargeObjectMetadataRelationId,
95 : RowExclusiveLock);
96 :
97 44 : pg_largeobject = table_open(LargeObjectRelationId,
98 : RowExclusiveLock);
99 :
100 : /*
101 : * Delete an entry from pg_largeobject_metadata
102 : */
7088 tgl 103 44 : ScanKeyInit(&skey[0],
104 : Anum_pg_largeobject_metadata_oid,
105 : BTEqualStrategyNumber, F_OIDEQ,
106 : ObjectIdGetDatum(loid));
107 :
4867 itagaki.takahiro 108 44 : scan = systable_beginscan(pg_lo_meta,
109 : LargeObjectMetadataOidIndexId, true,
110 : NULL, 1, skey);
111 :
112 44 : tuple = systable_getnext(scan);
113 44 : if (!HeapTupleIsValid(tuple))
4867 itagaki.takahiro 114 UBC 0 : ereport(ERROR,
115 : (errcode(ERRCODE_UNDEFINED_OBJECT),
116 : errmsg("large object %u does not exist", loid)));
117 :
2258 tgl 118 CBC 44 : CatalogTupleDelete(pg_lo_meta, &tuple->t_self);
119 :
4867 itagaki.takahiro 120 44 : systable_endscan(scan);
121 :
122 : /*
123 : * Delete all the associated entries from pg_largeobject
124 : */
125 44 : ScanKeyInit(&skey[0],
126 : Anum_pg_largeobject_loid,
127 : BTEqualStrategyNumber, F_OIDEQ,
128 : ObjectIdGetDatum(loid));
129 :
130 44 : scan = systable_beginscan(pg_largeobject,
131 : LargeObjectLOidPNIndexId, true,
132 : NULL, 1, skey);
133 4007 : while (HeapTupleIsValid(tuple = systable_getnext(scan)))
134 : {
2258 tgl 135 3963 : CatalogTupleDelete(pg_largeobject, &tuple->t_self);
136 : }
137 :
4867 itagaki.takahiro 138 44 : systable_endscan(scan);
139 :
1539 andres 140 44 : table_close(pg_largeobject, RowExclusiveLock);
141 :
142 44 : table_close(pg_lo_meta, RowExclusiveLock);
4867 itagaki.takahiro 143 44 : }
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 : */
157 : bool
8202 tgl 158 74 : LargeObjectExists(Oid loid)
159 : {
160 : Relation pg_lo_meta;
161 : ScanKeyData skey[1];
162 : SysScanDesc sd;
163 : HeapTuple tuple;
164 74 : bool retval = false;
165 :
7088 166 74 : ScanKeyInit(&skey[0],
167 : Anum_pg_largeobject_metadata_oid,
168 : BTEqualStrategyNumber, F_OIDEQ,
169 : ObjectIdGetDatum(loid));
170 :
1539 andres 171 74 : pg_lo_meta = table_open(LargeObjectMetadataRelationId,
172 : AccessShareLock);
173 :
4867 itagaki.takahiro 174 74 : sd = systable_beginscan(pg_lo_meta,
175 : LargeObjectMetadataOidIndexId, true,
176 : NULL, 1, skey);
177 :
178 74 : tuple = systable_getnext(sd);
179 74 : if (HeapTupleIsValid(tuple))
7629 tgl 180 56 : retval = true;
181 :
7137 182 74 : systable_endscan(sd);
183 :
1539 andres 184 74 : table_close(pg_lo_meta, AccessShareLock);
185 :
8202 tgl 186 74 : return retval;
187 : }
|