]> granicus.if.org Git - postgresql/blob - src/backend/catalog/pg_conversion.c
Restructure some header files a bit, in particular heapam.h, by removing some
[postgresql] / src / backend / catalog / pg_conversion.c
1 /*-------------------------------------------------------------------------
2  *
3  * pg_conversion.c
4  *        routines to support manipulation of the pg_conversion relation
5  *
6  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $PostgreSQL: pgsql/src/backend/catalog/pg_conversion.c,v 1.43 2008/05/12 00:00:47 alvherre Exp $
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16
17 #include "access/heapam.h"
18 #include "access/sysattr.h"
19 #include "catalog/dependency.h"
20 #include "catalog/indexing.h"
21 #include "catalog/namespace.h"
22 #include "catalog/pg_conversion.h"
23 #include "catalog/pg_conversion_fn.h"
24 #include "catalog/pg_namespace.h"
25 #include "catalog/pg_proc.h"
26 #include "mb/pg_wchar.h"
27 #include "miscadmin.h"
28 #include "utils/acl.h"
29 #include "utils/builtins.h"
30 #include "utils/fmgroids.h"
31 #include "utils/syscache.h"
32 #include "utils/tqual.h"
33
34 /*
35  * ConversionCreate
36  *
37  * Add a new tuple to pg_conversion.
38  */
39 Oid
40 ConversionCreate(const char *conname, Oid connamespace,
41                                  Oid conowner,
42                                  int32 conforencoding, int32 contoencoding,
43                                  Oid conproc, bool def)
44 {
45         int                     i;
46         Relation        rel;
47         TupleDesc       tupDesc;
48         HeapTuple       tup;
49         char            nulls[Natts_pg_conversion];
50         Datum           values[Natts_pg_conversion];
51         NameData        cname;
52         Oid                     oid;
53         ObjectAddress myself,
54                                 referenced;
55
56         /* sanity checks */
57         if (!conname)
58                 elog(ERROR, "no conversion name supplied");
59
60         /* make sure there is no existing conversion of same name */
61         if (SearchSysCacheExists(CONNAMENSP,
62                                                          PointerGetDatum(conname),
63                                                          ObjectIdGetDatum(connamespace),
64                                                          0, 0))
65                 ereport(ERROR,
66                                 (errcode(ERRCODE_DUPLICATE_OBJECT),
67                                  errmsg("conversion \"%s\" already exists", conname)));
68
69         if (def)
70         {
71                 /*
72                  * make sure there is no existing default <for encoding><to encoding>
73                  * pair in this name space
74                  */
75                 if (FindDefaultConversion(connamespace,
76                                                                   conforencoding,
77                                                                   contoencoding))
78                         ereport(ERROR,
79                                         (errcode(ERRCODE_DUPLICATE_OBJECT),
80                                          errmsg("default conversion for %s to %s already exists",
81                                                         pg_encoding_to_char(conforencoding),
82                                                         pg_encoding_to_char(contoencoding))));
83         }
84
85         /* open pg_conversion */
86         rel = heap_open(ConversionRelationId, RowExclusiveLock);
87         tupDesc = rel->rd_att;
88
89         /* initialize nulls and values */
90         for (i = 0; i < Natts_pg_conversion; i++)
91         {
92                 nulls[i] = ' ';
93                 values[i] = (Datum) NULL;
94         }
95
96         /* form a tuple */
97         namestrcpy(&cname, conname);
98         values[Anum_pg_conversion_conname - 1] = NameGetDatum(&cname);
99         values[Anum_pg_conversion_connamespace - 1] = ObjectIdGetDatum(connamespace);
100         values[Anum_pg_conversion_conowner - 1] = ObjectIdGetDatum(conowner);
101         values[Anum_pg_conversion_conforencoding - 1] = Int32GetDatum(conforencoding);
102         values[Anum_pg_conversion_contoencoding - 1] = Int32GetDatum(contoencoding);
103         values[Anum_pg_conversion_conproc - 1] = ObjectIdGetDatum(conproc);
104         values[Anum_pg_conversion_condefault - 1] = BoolGetDatum(def);
105
106         tup = heap_formtuple(tupDesc, values, nulls);
107
108         /* insert a new tuple */
109         oid = simple_heap_insert(rel, tup);
110         Assert(OidIsValid(oid));
111
112         /* update the index if any */
113         CatalogUpdateIndexes(rel, tup);
114
115         myself.classId = ConversionRelationId;
116         myself.objectId = HeapTupleGetOid(tup);
117         myself.objectSubId = 0;
118
119         /* create dependency on conversion procedure */
120         referenced.classId = ProcedureRelationId;
121         referenced.objectId = conproc;
122         referenced.objectSubId = 0;
123         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
124
125         /* create dependency on namespace */
126         referenced.classId = NamespaceRelationId;
127         referenced.objectId = connamespace;
128         referenced.objectSubId = 0;
129         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
130
131         /* create dependency on owner */
132         recordDependencyOnOwner(ConversionRelationId, HeapTupleGetOid(tup),
133                                                         conowner);
134
135         heap_freetuple(tup);
136         heap_close(rel, RowExclusiveLock);
137
138         return oid;
139 }
140
141 /*
142  * ConversionDrop
143  *
144  * Drop a conversion after doing permission checks.
145  */
146 void
147 ConversionDrop(Oid conversionOid, DropBehavior behavior)
148 {
149         HeapTuple       tuple;
150         ObjectAddress object;
151
152         tuple = SearchSysCache(CONVOID,
153                                                    ObjectIdGetDatum(conversionOid),
154                                                    0, 0, 0);
155         if (!HeapTupleIsValid(tuple))
156                 elog(ERROR, "cache lookup failed for conversion %u", conversionOid);
157
158         if (!superuser() &&
159                 ((Form_pg_conversion) GETSTRUCT(tuple))->conowner != GetUserId())
160                 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CONVERSION,
161                                   NameStr(((Form_pg_conversion) GETSTRUCT(tuple))->conname));
162
163         ReleaseSysCache(tuple);
164
165         /*
166          * Do the deletion
167          */
168         object.classId = ConversionRelationId;
169         object.objectId = conversionOid;
170         object.objectSubId = 0;
171
172         performDeletion(&object, behavior);
173 }
174
175 /*
176  * RemoveConversionById
177  *
178  * Remove a tuple from pg_conversion by Oid. This function is solely
179  * called inside catalog/dependency.c
180  */
181 void
182 RemoveConversionById(Oid conversionOid)
183 {
184         Relation        rel;
185         HeapTuple       tuple;
186         HeapScanDesc scan;
187         ScanKeyData scanKeyData;
188
189         ScanKeyInit(&scanKeyData,
190                                 ObjectIdAttributeNumber,
191                                 BTEqualStrategyNumber, F_OIDEQ,
192                                 ObjectIdGetDatum(conversionOid));
193
194         /* open pg_conversion */
195         rel = heap_open(ConversionRelationId, RowExclusiveLock);
196
197         scan = heap_beginscan(rel, SnapshotNow,
198                                                   1, &scanKeyData);
199
200         /* search for the target tuple */
201         if (HeapTupleIsValid(tuple = heap_getnext(scan, ForwardScanDirection)))
202                 simple_heap_delete(rel, &tuple->t_self);
203         else
204                 elog(ERROR, "could not find tuple for conversion %u", conversionOid);
205         heap_endscan(scan);
206         heap_close(rel, RowExclusiveLock);
207 }
208
209 /*
210  * FindDefaultConversion
211  *
212  * Find "default" conversion proc by for_encoding and to_encoding in the
213  * given namespace.
214  *
215  * If found, returns the procedure's oid, otherwise InvalidOid.  Note that
216  * you get the procedure's OID not the conversion's OID!
217  */
218 Oid
219 FindDefaultConversion(Oid name_space, int32 for_encoding, int32 to_encoding)
220 {
221         CatCList   *catlist;
222         HeapTuple       tuple;
223         Form_pg_conversion body;
224         Oid                     proc = InvalidOid;
225         int                     i;
226
227         catlist = SearchSysCacheList(CONDEFAULT, 3,
228                                                                  ObjectIdGetDatum(name_space),
229                                                                  Int32GetDatum(for_encoding),
230                                                                  Int32GetDatum(to_encoding),
231                                                                  0);
232
233         for (i = 0; i < catlist->n_members; i++)
234         {
235                 tuple = &catlist->members[i]->tuple;
236                 body = (Form_pg_conversion) GETSTRUCT(tuple);
237                 if (body->condefault)
238                 {
239                         proc = body->conproc;
240                         break;
241                 }
242         }
243         ReleaseSysCacheList(catlist);
244         return proc;
245 }
246
247 /*
248  * FindConversion
249  *
250  * Find conversion by namespace and conversion name.
251  * Returns conversion OID.
252  */
253 Oid
254 FindConversion(const char *conname, Oid connamespace)
255 {
256         HeapTuple       tuple;
257         Oid                     procoid;
258         Oid                     conoid;
259         AclResult       aclresult;
260
261         /* search pg_conversion by connamespace and conversion name */
262         tuple = SearchSysCache(CONNAMENSP,
263                                                    PointerGetDatum(conname),
264                                                    ObjectIdGetDatum(connamespace),
265                                                    0, 0);
266         if (!HeapTupleIsValid(tuple))
267                 return InvalidOid;
268
269         procoid = ((Form_pg_conversion) GETSTRUCT(tuple))->conproc;
270         conoid = HeapTupleGetOid(tuple);
271
272         ReleaseSysCache(tuple);
273
274         /* Check we have execute rights for the function */
275         aclresult = pg_proc_aclcheck(procoid, GetUserId(), ACL_EXECUTE);
276         if (aclresult != ACLCHECK_OK)
277                 return InvalidOid;
278
279         return conoid;
280 }