~vcs-imports/mammoth-replicator/trunk

« back to all changes in this revision

Viewing changes to src/backend/catalog/pg_conversion.c

  • Committer: alvherre
  • Date: 2005-12-16 21:24:52 UTC
  • Revision ID: svn-v4:db760fc0-0f08-0410-9d63-cc6633f64896:trunk:1
Initial import of the REL8_0_3 sources from the Pgsql CVS repository.

Show diffs side-by-side

added added

removed removed

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