1
/*-------------------------------------------------------------------------
4
* routines to support manipulation of the pg_conversion relation
6
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
7
* Portions Copyright (c) 1994, Regents of the University of California
11
* $PostgreSQL: pgsql/src/backend/catalog/pg_conversion.c,v 1.20 2004-12-31 21:59:38 pgsql Exp $
13
*-------------------------------------------------------------------------
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"
36
* Add a new tuple to pg_conversion.
39
ConversionCreate(const char *conname, Oid connamespace,
41
int32 conforencoding, int32 contoencoding,
42
Oid conproc, bool def)
48
char nulls[Natts_pg_conversion];
49
Datum values[Natts_pg_conversion];
57
elog(ERROR, "no conversion name supplied");
59
/* make sure there is no existing conversion of same name */
60
if (SearchSysCacheExists(CONNAMENSP,
61
PointerGetDatum(conname),
62
ObjectIdGetDatum(connamespace),
65
(errcode(ERRCODE_DUPLICATE_OBJECT),
66
errmsg("conversion \"%s\" already exists", conname)));
71
* make sure there is no existing default <for encoding><to
72
* encoding> pair in this name space
74
if (FindDefaultConversion(connamespace,
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))));
84
/* open pg_conversion */
85
rel = heap_openr(ConversionRelationName, RowExclusiveLock);
86
tupDesc = rel->rd_att;
88
/* initialize nulls and values */
89
for (i = 0; i < Natts_pg_conversion; i++)
92
values[i] = (Datum) NULL;
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);
105
tup = heap_formtuple(tupDesc, values, nulls);
107
/* insert a new tuple */
108
oid = simple_heap_insert(rel, tup);
109
Assert(OidIsValid(oid));
111
/* update the index if any */
112
CatalogUpdateIndexes(rel, tup);
114
myself.classId = RelationGetRelid(rel);
115
myself.objectId = HeapTupleGetOid(tup);
116
myself.objectSubId = 0;
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);
125
heap_close(rel, RowExclusiveLock);
133
* Drop a conversion after doing permission checks.
136
ConversionDrop(Oid conversionOid, DropBehavior behavior)
139
ObjectAddress object;
141
tuple = SearchSysCache(CONOID,
142
ObjectIdGetDatum(conversionOid),
144
if (!HeapTupleIsValid(tuple))
145
elog(ERROR, "cache lookup failed for conversion %u", conversionOid);
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));
152
ReleaseSysCache(tuple);
157
object.classId = get_system_catalog_relid(ConversionRelationName);
158
object.objectId = conversionOid;
159
object.objectSubId = 0;
161
performDeletion(&object, behavior);
165
* RemoveConversionById
167
* Remove a tuple from pg_conversion by Oid. This function is solely
168
* called inside catalog/dependency.c
171
RemoveConversionById(Oid conversionOid)
177
ScanKeyData scanKeyData;
179
ScanKeyInit(&scanKeyData,
180
ObjectIdAttributeNumber,
181
BTEqualStrategyNumber, F_OIDEQ,
182
ObjectIdGetDatum(conversionOid));
184
/* open pg_conversion */
185
rel = heap_openr(ConversionRelationName, RowExclusiveLock);
186
tupDesc = rel->rd_att;
188
scan = heap_beginscan(rel, SnapshotNow,
191
/* search for the target tuple */
192
if (HeapTupleIsValid(tuple = heap_getnext(scan, ForwardScanDirection)))
193
simple_heap_delete(rel, &tuple->t_self);
195
elog(ERROR, "could not find tuple for conversion %u", conversionOid);
197
heap_close(rel, RowExclusiveLock);
201
* FindDefaultConversion
203
* Find "default" conversion proc by for_encoding and to_encoding in the
206
* If found, returns the procedure's oid, otherwise InvalidOid. Note that
207
* you get the procedure's OID not the conversion's OID!
210
FindDefaultConversion(Oid name_space, int32 for_encoding, int32 to_encoding)
214
Form_pg_conversion body;
215
Oid proc = InvalidOid;
218
catlist = SearchSysCacheList(CONDEFAULT, 3,
219
ObjectIdGetDatum(name_space),
220
Int32GetDatum(for_encoding),
221
Int32GetDatum(to_encoding),
224
for (i = 0; i < catlist->n_members; i++)
226
tuple = &catlist->members[i]->tuple;
227
body = (Form_pg_conversion) GETSTRUCT(tuple);
228
if (body->condefault)
230
proc = body->conproc;
234
ReleaseSysCacheList(catlist);
241
* Find conversion by namespace and conversion name.
242
* Returns conversion OID.
245
FindConversion(const char *conname, Oid connamespace)
252
/* search pg_conversion by connamespace and conversion name */
253
tuple = SearchSysCache(CONNAMENSP,
254
PointerGetDatum(conname),
255
ObjectIdGetDatum(connamespace),
257
if (!HeapTupleIsValid(tuple))
260
procoid = ((Form_pg_conversion) GETSTRUCT(tuple))->conproc;
261
conoid = HeapTupleGetOid(tuple);
263
ReleaseSysCache(tuple);
265
/* Check we have execute rights for the function */
266
aclresult = pg_proc_aclcheck(procoid, GetUserId(), ACL_EXECUTE);
267
if (aclresult != ACLCHECK_OK)
274
* Execute SQL99's CONVERT function.
276
* CONVERT <left paren> <character value expression>
277
* USING <form-of-use conversion name> <right paren>
279
* TEXT convert_using(TEXT string, TEXT conversion_name)
282
pg_convert_using(PG_FUNCTION_ARGS)
284
text *string = PG_GETARG_TEXT_P(0);
285
text *conv_name = PG_GETARG_TEXT_P(1);
290
Form_pg_conversion body;
292
unsigned char *result;
295
/* Convert input string to null-terminated form */
296
len = VARSIZE(string) - VARHDRSZ;
297
str = palloc(len + 1);
298
memcpy(str, VARDATA(string), len);
301
/* Look up the conversion name */
302
parsed_name = textToQualifiedNameList(conv_name, "convert_using");
303
convoid = FindConversionByName(parsed_name);
304
if (!OidIsValid(convoid))
306
(errcode(ERRCODE_UNDEFINED_OBJECT),
307
errmsg("conversion \"%s\" does not exist",
308
NameListToString(parsed_name))));
310
tuple = SearchSysCache(CONOID,
311
ObjectIdGetDatum(convoid),
313
if (!HeapTupleIsValid(tuple))
314
elog(ERROR, "cache lookup failed for conversion %u", convoid);
315
body = (Form_pg_conversion) GETSTRUCT(tuple);
317
/* Temporary result area should be more than big enough */
318
result = palloc(len * 4 + 1);
320
OidFunctionCall5(body->conproc,
321
Int32GetDatum(body->conforencoding),
322
Int32GetDatum(body->contoencoding),
323
CStringGetDatum(str),
324
CStringGetDatum(result),
327
ReleaseSysCache(tuple);
330
* build text result structure. we cannot use textin() here, since
331
* textin assumes that input string encoding is same as database
334
len = strlen(result) + VARHDRSZ;
335
retval = palloc(len);
336
VARATT_SIZEP(retval) = len;
337
memcpy(VARDATA(retval), result, len - VARHDRSZ);
342
PG_RETURN_TEXT_P(retval);