1 /*-------------------------------------------------------------------------
4 * routines to support manipulation of the pg_conversion relation
6 * Portions Copyright (c) 1996-2007, 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.35 2007/02/14 01:58:56 tgl Exp $
13 *-------------------------------------------------------------------------
17 #include "access/heapam.h"
18 #include "catalog/dependency.h"
19 #include "catalog/indexing.h"
20 #include "catalog/namespace.h"
21 #include "catalog/pg_conversion.h"
22 #include "catalog/pg_namespace.h"
23 #include "catalog/pg_proc.h"
24 #include "mb/pg_wchar.h"
25 #include "utils/builtins.h"
26 #include "utils/fmgroids.h"
27 #include "utils/syscache.h"
28 #include "utils/acl.h"
29 #include "miscadmin.h"
34 * Add a new tuple to pg_conversion.
37 ConversionCreate(const char *conname, Oid connamespace,
39 int32 conforencoding, int32 contoencoding,
40 Oid conproc, bool def)
46 char nulls[Natts_pg_conversion];
47 Datum values[Natts_pg_conversion];
55 elog(ERROR, "no conversion name supplied");
57 /* make sure there is no existing conversion of same name */
58 if (SearchSysCacheExists(CONNAMENSP,
59 PointerGetDatum(conname),
60 ObjectIdGetDatum(connamespace),
63 (errcode(ERRCODE_DUPLICATE_OBJECT),
64 errmsg("conversion \"%s\" already exists", conname)));
69 * make sure there is no existing default <for encoding><to encoding>
70 * pair in this name space
72 if (FindDefaultConversion(connamespace,
76 (errcode(ERRCODE_DUPLICATE_OBJECT),
77 errmsg("default conversion for %s to %s already exists",
78 pg_encoding_to_char(conforencoding),
79 pg_encoding_to_char(contoencoding))));
82 /* open pg_conversion */
83 rel = heap_open(ConversionRelationId, RowExclusiveLock);
84 tupDesc = rel->rd_att;
86 /* initialize nulls and values */
87 for (i = 0; i < Natts_pg_conversion; i++)
90 values[i] = (Datum) NULL;
94 namestrcpy(&cname, conname);
95 values[Anum_pg_conversion_conname - 1] = NameGetDatum(&cname);
96 values[Anum_pg_conversion_connamespace - 1] = ObjectIdGetDatum(connamespace);
97 values[Anum_pg_conversion_conowner - 1] = ObjectIdGetDatum(conowner);
98 values[Anum_pg_conversion_conforencoding - 1] = Int32GetDatum(conforencoding);
99 values[Anum_pg_conversion_contoencoding - 1] = Int32GetDatum(contoencoding);
100 values[Anum_pg_conversion_conproc - 1] = ObjectIdGetDatum(conproc);
101 values[Anum_pg_conversion_condefault - 1] = BoolGetDatum(def);
103 tup = heap_formtuple(tupDesc, values, nulls);
105 /* insert a new tuple */
106 oid = simple_heap_insert(rel, tup);
107 Assert(OidIsValid(oid));
109 /* update the index if any */
110 CatalogUpdateIndexes(rel, tup);
112 myself.classId = ConversionRelationId;
113 myself.objectId = HeapTupleGetOid(tup);
114 myself.objectSubId = 0;
116 /* create dependency on conversion procedure */
117 referenced.classId = ProcedureRelationId;
118 referenced.objectId = conproc;
119 referenced.objectSubId = 0;
120 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
122 /* create dependency on namespace */
123 referenced.classId = NamespaceRelationId;
124 referenced.objectId = connamespace;
125 referenced.objectSubId = 0;
126 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
128 /* create dependency on owner */
129 recordDependencyOnOwner(ConversionRelationId, HeapTupleGetOid(tup),
133 heap_close(rel, RowExclusiveLock);
141 * Drop a conversion after doing permission checks.
144 ConversionDrop(Oid conversionOid, DropBehavior behavior)
147 ObjectAddress object;
149 tuple = SearchSysCache(CONVOID,
150 ObjectIdGetDatum(conversionOid),
152 if (!HeapTupleIsValid(tuple))
153 elog(ERROR, "cache lookup failed for conversion %u", conversionOid);
156 ((Form_pg_conversion) GETSTRUCT(tuple))->conowner != GetUserId())
157 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CONVERSION,
158 NameStr(((Form_pg_conversion) GETSTRUCT(tuple))->conname));
160 ReleaseSysCache(tuple);
165 object.classId = ConversionRelationId;
166 object.objectId = conversionOid;
167 object.objectSubId = 0;
169 performDeletion(&object, behavior);
173 * RemoveConversionById
175 * Remove a tuple from pg_conversion by Oid. This function is solely
176 * called inside catalog/dependency.c
179 RemoveConversionById(Oid conversionOid)
184 ScanKeyData scanKeyData;
186 ScanKeyInit(&scanKeyData,
187 ObjectIdAttributeNumber,
188 BTEqualStrategyNumber, F_OIDEQ,
189 ObjectIdGetDatum(conversionOid));
191 /* open pg_conversion */
192 rel = heap_open(ConversionRelationId, RowExclusiveLock);
194 scan = heap_beginscan(rel, SnapshotNow,
197 /* search for the target tuple */
198 if (HeapTupleIsValid(tuple = heap_getnext(scan, ForwardScanDirection)))
199 simple_heap_delete(rel, &tuple->t_self);
201 elog(ERROR, "could not find tuple for conversion %u", conversionOid);
203 heap_close(rel, RowExclusiveLock);
207 * FindDefaultConversion
209 * Find "default" conversion proc by for_encoding and to_encoding in the
212 * If found, returns the procedure's oid, otherwise InvalidOid. Note that
213 * you get the procedure's OID not the conversion's OID!
216 FindDefaultConversion(Oid name_space, int32 for_encoding, int32 to_encoding)
220 Form_pg_conversion body;
221 Oid proc = InvalidOid;
224 catlist = SearchSysCacheList(CONDEFAULT, 3,
225 ObjectIdGetDatum(name_space),
226 Int32GetDatum(for_encoding),
227 Int32GetDatum(to_encoding),
230 for (i = 0; i < catlist->n_members; i++)
232 tuple = &catlist->members[i]->tuple;
233 body = (Form_pg_conversion) GETSTRUCT(tuple);
234 if (body->condefault)
236 proc = body->conproc;
240 ReleaseSysCacheList(catlist);
247 * Find conversion by namespace and conversion name.
248 * Returns conversion OID.
251 FindConversion(const char *conname, Oid connamespace)
258 /* search pg_conversion by connamespace and conversion name */
259 tuple = SearchSysCache(CONNAMENSP,
260 PointerGetDatum(conname),
261 ObjectIdGetDatum(connamespace),
263 if (!HeapTupleIsValid(tuple))
266 procoid = ((Form_pg_conversion) GETSTRUCT(tuple))->conproc;
267 conoid = HeapTupleGetOid(tuple);
269 ReleaseSysCache(tuple);
271 /* Check we have execute rights for the function */
272 aclresult = pg_proc_aclcheck(procoid, GetUserId(), ACL_EXECUTE);
273 if (aclresult != ACLCHECK_OK)
280 * Execute SQL99's CONVERT function.
282 * CONVERT <left paren> <character value expression>
283 * USING <form-of-use conversion name> <right paren>
285 * TEXT convert_using(TEXT string, TEXT conversion_name)
288 pg_convert_using(PG_FUNCTION_ARGS)
290 text *string = PG_GETARG_TEXT_P(0);
291 text *conv_name = PG_GETARG_TEXT_P(1);
296 Form_pg_conversion body;
301 /* Convert input string to null-terminated form */
302 len = VARSIZE(string) - VARHDRSZ;
303 str = palloc(len + 1);
304 memcpy(str, VARDATA(string), len);
307 /* Look up the conversion name */
308 parsed_name = textToQualifiedNameList(conv_name);
309 convoid = FindConversionByName(parsed_name);
310 if (!OidIsValid(convoid))
312 (errcode(ERRCODE_UNDEFINED_OBJECT),
313 errmsg("conversion \"%s\" does not exist",
314 NameListToString(parsed_name))));
316 tuple = SearchSysCache(CONVOID,
317 ObjectIdGetDatum(convoid),
319 if (!HeapTupleIsValid(tuple))
320 elog(ERROR, "cache lookup failed for conversion %u", convoid);
321 body = (Form_pg_conversion) GETSTRUCT(tuple);
323 /* Temporary result area should be more than big enough */
324 result = palloc(len * 4 + 1);
326 OidFunctionCall5(body->conproc,
327 Int32GetDatum(body->conforencoding),
328 Int32GetDatum(body->contoencoding),
329 CStringGetDatum(str),
330 CStringGetDatum(result),
333 ReleaseSysCache(tuple);
336 * build text result structure. we cannot use textin() here, since textin
337 * assumes that input string encoding is same as database encoding.
339 len = strlen(result) + VARHDRSZ;
340 retval = palloc(len);
341 VARATT_SIZEP(retval) = len;
342 memcpy(VARDATA(retval), result, len - VARHDRSZ);
347 PG_RETURN_TEXT_P(retval);