OSDN Git Service

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