]> granicus.if.org Git - postgresql/blob - src/backend/catalog/pg_conversion.c
Replace pg_shadow and pg_group by new role-capable catalogs pg_authid
[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-2005, 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.24 2005/06/28 05:08:52 tgl Exp $
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16
17 #include "access/heapam.h"
18 #include "catalog/dependency.h"
19 #include "catalog/indexing.h"
20 #include "catalog/pg_conversion.h"
21 #include "catalog/pg_proc.h"
22 #include "catalog/namespace.h"
23 #include "utils/builtins.h"
24 #include "utils/lsyscache.h"
25 #include "utils/syscache.h"
26 #include "utils/catcache.h"
27 #include "mb/pg_wchar.h"
28 #include "utils/fmgroids.h"
29 #include "utils/acl.h"
30 #include "miscadmin.h"
31
32 /*
33  * ConversionCreate
34  *
35  * Add a new tuple to pg_conversion.
36  */
37 Oid
38 ConversionCreate(const char *conname, Oid connamespace,
39                                  Oid conowner,
40                                  int32 conforencoding, int32 contoencoding,
41                                  Oid conproc, bool def)
42 {
43         int                     i;
44         Relation        rel;
45         TupleDesc       tupDesc;
46         HeapTuple       tup;
47         char            nulls[Natts_pg_conversion];
48         Datum           values[Natts_pg_conversion];
49         NameData        cname;
50         Oid                     oid;
51         ObjectAddress myself,
52                                 referenced;
53
54         /* sanity checks */
55         if (!conname)
56                 elog(ERROR, "no conversion name supplied");
57
58         /* make sure there is no existing conversion of same name */
59         if (SearchSysCacheExists(CONNAMENSP,
60                                                          PointerGetDatum(conname),
61                                                          ObjectIdGetDatum(connamespace),
62                                                          0, 0))
63                 ereport(ERROR,
64                                 (errcode(ERRCODE_DUPLICATE_OBJECT),
65                                  errmsg("conversion \"%s\" already exists", conname)));
66
67         if (def)
68         {
69                 /*
70                  * make sure there is no existing default <for encoding><to
71                  * encoding> pair in this name space
72                  */
73                 if (FindDefaultConversion(connamespace,
74                                                                   conforencoding,
75                                                                   contoencoding))
76                         ereport(ERROR,
77                                         (errcode(ERRCODE_DUPLICATE_OBJECT),
78                                  errmsg("default conversion for %s to %s already exists",
79                                                 pg_encoding_to_char(conforencoding),
80                                                 pg_encoding_to_char(contoencoding))));
81         }
82
83         /* open pg_conversion */
84         rel = heap_open(ConversionRelationId, RowExclusiveLock);
85         tupDesc = rel->rd_att;
86
87         /* initialize nulls and values */
88         for (i = 0; i < Natts_pg_conversion; i++)
89         {
90                 nulls[i] = ' ';
91                 values[i] = (Datum) NULL;
92         }
93
94         /* form a tuple */
95         namestrcpy(&cname, conname);
96         values[Anum_pg_conversion_conname - 1] = NameGetDatum(&cname);
97         values[Anum_pg_conversion_connamespace - 1] = ObjectIdGetDatum(connamespace);
98         values[Anum_pg_conversion_conowner - 1] = ObjectIdGetDatum(conowner);
99         values[Anum_pg_conversion_conforencoding - 1] = Int32GetDatum(conforencoding);
100         values[Anum_pg_conversion_contoencoding - 1] = Int32GetDatum(contoencoding);
101         values[Anum_pg_conversion_conproc - 1] = ObjectIdGetDatum(conproc);
102         values[Anum_pg_conversion_condefault - 1] = BoolGetDatum(def);
103
104         tup = heap_formtuple(tupDesc, values, nulls);
105
106         /* insert a new tuple */
107         oid = simple_heap_insert(rel, tup);
108         Assert(OidIsValid(oid));
109
110         /* update the index if any */
111         CatalogUpdateIndexes(rel, tup);
112
113         myself.classId = ConversionRelationId;
114         myself.objectId = HeapTupleGetOid(tup);
115         myself.objectSubId = 0;
116
117         /* create dependency on conversion procedure */
118         referenced.classId = ProcedureRelationId;
119         referenced.objectId = conproc;
120         referenced.objectSubId = 0;
121         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
122
123         heap_freetuple(tup);
124         heap_close(rel, RowExclusiveLock);
125
126         return oid;
127 }
128
129 /*
130  * ConversionDrop
131  *
132  * Drop a conversion after doing permission checks.
133  */
134 void
135 ConversionDrop(Oid conversionOid, DropBehavior behavior)
136 {
137         HeapTuple       tuple;
138         ObjectAddress object;
139
140         tuple = SearchSysCache(CONOID,
141                                                    ObjectIdGetDatum(conversionOid),
142                                                    0, 0, 0);
143         if (!HeapTupleIsValid(tuple))
144                 elog(ERROR, "cache lookup failed for conversion %u", conversionOid);
145
146         if (!superuser() &&
147                 ((Form_pg_conversion) GETSTRUCT(tuple))->conowner != GetUserId())
148                 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CONVERSION,
149                           NameStr(((Form_pg_conversion) GETSTRUCT(tuple))->conname));
150
151         ReleaseSysCache(tuple);
152
153         /*
154          * Do the deletion
155          */
156         object.classId = ConversionRelationId;
157         object.objectId = conversionOid;
158         object.objectSubId = 0;
159
160         performDeletion(&object, behavior);
161 }
162
163 /*
164  * RemoveConversionById
165  *
166  * Remove a tuple from pg_conversion by Oid. This function is solely
167  * called inside catalog/dependency.c
168  */
169 void
170 RemoveConversionById(Oid conversionOid)
171 {
172         Relation        rel;
173         TupleDesc       tupDesc;
174         HeapTuple       tuple;
175         HeapScanDesc scan;
176         ScanKeyData scanKeyData;
177
178         ScanKeyInit(&scanKeyData,
179                                 ObjectIdAttributeNumber,
180                                 BTEqualStrategyNumber, F_OIDEQ,
181                                 ObjectIdGetDatum(conversionOid));
182
183         /* open pg_conversion */
184         rel = heap_open(ConversionRelationId, RowExclusiveLock);
185         tupDesc = rel->rd_att;
186
187         scan = heap_beginscan(rel, SnapshotNow,
188                                                   1, &scanKeyData);
189
190         /* search for the target tuple */
191         if (HeapTupleIsValid(tuple = heap_getnext(scan, ForwardScanDirection)))
192                 simple_heap_delete(rel, &tuple->t_self);
193         else
194                 elog(ERROR, "could not find tuple for conversion %u", conversionOid);
195         heap_endscan(scan);
196         heap_close(rel, RowExclusiveLock);
197 }
198
199 /*
200  * FindDefaultConversion
201  *
202  * Find "default" conversion proc by for_encoding and to_encoding in the
203  * given namespace.
204  *
205  * If found, returns the procedure's oid, otherwise InvalidOid.  Note that
206  * you get the procedure's OID not the conversion's OID!
207  */
208 Oid
209 FindDefaultConversion(Oid name_space, int32 for_encoding, int32 to_encoding)
210 {
211         CatCList   *catlist;
212         HeapTuple       tuple;
213         Form_pg_conversion body;
214         Oid                     proc = InvalidOid;
215         int                     i;
216
217         catlist = SearchSysCacheList(CONDEFAULT, 3,
218                                                                  ObjectIdGetDatum(name_space),
219                                                                  Int32GetDatum(for_encoding),
220                                                                  Int32GetDatum(to_encoding),
221                                                                  0);
222
223         for (i = 0; i < catlist->n_members; i++)
224         {
225                 tuple = &catlist->members[i]->tuple;
226                 body = (Form_pg_conversion) GETSTRUCT(tuple);
227                 if (body->condefault)
228                 {
229                         proc = body->conproc;
230                         break;
231                 }
232         }
233         ReleaseSysCacheList(catlist);
234         return proc;
235 }
236
237 /*
238  * FindConversion
239  *
240  * Find conversion by namespace and conversion name.
241  * Returns conversion OID.
242  */
243 Oid
244 FindConversion(const char *conname, Oid connamespace)
245 {
246         HeapTuple       tuple;
247         Oid                     procoid;
248         Oid                     conoid;
249         AclResult       aclresult;
250
251         /* search pg_conversion by connamespace and conversion name */
252         tuple = SearchSysCache(CONNAMENSP,
253                                                    PointerGetDatum(conname),
254                                                    ObjectIdGetDatum(connamespace),
255                                                    0, 0);
256         if (!HeapTupleIsValid(tuple))
257                 return InvalidOid;
258
259         procoid = ((Form_pg_conversion) GETSTRUCT(tuple))->conproc;
260         conoid = HeapTupleGetOid(tuple);
261
262         ReleaseSysCache(tuple);
263
264         /* Check we have execute rights for the function */
265         aclresult = pg_proc_aclcheck(procoid, GetUserId(), ACL_EXECUTE);
266         if (aclresult != ACLCHECK_OK)
267                 return InvalidOid;
268
269         return conoid;
270 }
271
272 /*
273  * Execute SQL99's CONVERT function.
274  *
275  * CONVERT <left paren> <character value expression>
276  * USING <form-of-use conversion name> <right paren>
277  *
278  * TEXT convert_using(TEXT string, TEXT conversion_name)
279  */
280 Datum
281 pg_convert_using(PG_FUNCTION_ARGS)
282 {
283         text       *string = PG_GETARG_TEXT_P(0);
284         text       *conv_name = PG_GETARG_TEXT_P(1);
285         text       *retval;
286         List       *parsed_name;
287         Oid                     convoid;
288         HeapTuple       tuple;
289         Form_pg_conversion body;
290         unsigned char *str;
291         unsigned char *result;
292         int                     len;
293
294         /* Convert input string to null-terminated form */
295         len = VARSIZE(string) - VARHDRSZ;
296         str = palloc(len + 1);
297         memcpy(str, VARDATA(string), len);
298         *(str + len) = '\0';
299
300         /* Look up the conversion name */
301         parsed_name = textToQualifiedNameList(conv_name);
302         convoid = FindConversionByName(parsed_name);
303         if (!OidIsValid(convoid))
304                 ereport(ERROR,
305                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
306                                  errmsg("conversion \"%s\" does not exist",
307                                                 NameListToString(parsed_name))));
308
309         tuple = SearchSysCache(CONOID,
310                                                    ObjectIdGetDatum(convoid),
311                                                    0, 0, 0);
312         if (!HeapTupleIsValid(tuple))
313                 elog(ERROR, "cache lookup failed for conversion %u", convoid);
314         body = (Form_pg_conversion) GETSTRUCT(tuple);
315
316         /* Temporary result area should be more than big enough */
317         result = palloc(len * 4 + 1);
318
319         OidFunctionCall5(body->conproc,
320                                          Int32GetDatum(body->conforencoding),
321                                          Int32GetDatum(body->contoencoding),
322                                          CStringGetDatum(str),
323                                          CStringGetDatum(result),
324                                          Int32GetDatum(len));
325
326         ReleaseSysCache(tuple);
327
328         /*
329          * build text result structure. we cannot use textin() here, since
330          * textin assumes that input string encoding is same as database
331          * encoding.
332          */
333         len = strlen(result) + VARHDRSZ;
334         retval = palloc(len);
335         VARATT_SIZEP(retval) = len;
336         memcpy(VARDATA(retval), result, len - VARHDRSZ);
337
338         pfree(result);
339         pfree(str);
340
341         PG_RETURN_TEXT_P(retval);
342 }