1 /*-------------------------------------------------------------------------
4 * routines to support manipulation of the pg_conversion relation
6 * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $Header: /cvsroot/pgsql/src/backend/catalog/pg_conversion.c,v 1.5 2002/08/06 05:40:45 ishii 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_coversion.
39 Oid ConversionCreate(const char *conname, Oid connamespace,
41 int4 conforencoding, int4 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(CONNAMESP,
61 PointerGetDatum(conname),
62 ObjectIdGetDatum(connamespace),
64 elog(ERROR, "conversion name \"%s\" already exists", conname);
68 /* make sure there is no existing default
69 <for encoding><to encoding> pair in this name space */
70 if (FindDefaultConversion(connamespace,
73 elog(ERROR, "default conversion for %s to %s already exists",
74 pg_encoding_to_char(conforencoding),pg_encoding_to_char(contoencoding));
77 /* open pg_conversion */
78 rel = heap_openr(ConversionRelationName, RowExclusiveLock);
79 tupDesc = rel->rd_att;
81 /* initialize nulls and values */
82 for (i = 0; i < Natts_pg_conversion; i++)
85 values[i] = (Datum) NULL;
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);
97 values[Anum_pg_conversion_condefault - 1] = BoolGetDatum(def);
99 nulls[Anum_pg_conversion_condefault - 1] = 'n';
101 tup = heap_formtuple(tupDesc, values, nulls);
103 /* insert a new tuple */
104 oid = simple_heap_insert(rel, tup);
105 Assert(OidIsValid(oid));
107 /* update the index if any */
108 CatalogUpdateIndexes(rel, tup);
110 myself.classId = get_system_catalog_relid(ConversionRelationName);
111 myself.objectId = HeapTupleGetOid(tup);
112 myself.objectSubId = 0;
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);
121 heap_close(rel, RowExclusiveLock);
129 * Drop a conversion and do dependency check.
132 void ConversionDrop(const char *conname, Oid connamespace,
133 int32 conowner, DropBehavior behavior)
139 ScanKeyData scanKeyData;
140 Form_pg_conversion body;
141 ObjectAddress object;
146 elog(ERROR, "no conversion name supplied");
148 ScanKeyEntryInitialize(&scanKeyData,
150 Anum_pg_conversion_connamespace,
152 ObjectIdGetDatum(connamespace));
154 /* open pg_conversion */
155 rel = heap_openr(ConversionRelationName, AccessShareLock);
156 tupDesc = rel->rd_att;
158 scan = heap_beginscan(rel, SnapshotNow,
161 /* search for the target tuple */
162 while (HeapTupleIsValid(tuple = heap_getnext(scan, ForwardScanDirection)))
164 body = (Form_pg_conversion)GETSTRUCT(tuple);
165 if (!strncmp(NameStr(body->conname), conname, NAMEDATALEN))
169 if (!HeapTupleIsValid(tuple))
171 elog(ERROR, "conversion %s not found", conname);
175 if (!superuser() && ((Form_pg_conversion)GETSTRUCT(tuple))->conowner != GetUserId())
176 elog(ERROR, "permission denied");
178 myoid = HeapTupleGetOid(tuple);
180 heap_close(rel, AccessShareLock);
185 object.classId = get_system_catalog_relid(ConversionRelationName);
186 object.objectId = myoid;
187 object.objectSubId = 0;
189 performDeletion(&object, behavior);
193 * RemoveConversionById
195 * Remove a tuple from pg_conversion by Oid. This function is soley
196 * called inside catalog/dependency.c
199 RemoveConversionById(Oid conversionOid)
205 ScanKeyData scanKeyData;
207 ScanKeyEntryInitialize(&scanKeyData,
209 ObjectIdAttributeNumber,
211 ObjectIdGetDatum(conversionOid));
213 /* open pg_conversion */
214 rel = heap_openr(ConversionRelationName, RowExclusiveLock);
215 tupDesc = rel->rd_att;
217 scan = heap_beginscan(rel, SnapshotNow,
220 /* search for the target tuple */
221 if (HeapTupleIsValid(tuple = heap_getnext(scan, ForwardScanDirection)))
222 simple_heap_delete(rel, &tuple->t_self);
224 elog(ERROR, "conversion %u does not exist", conversionOid);
226 heap_close(rel, RowExclusiveLock);
230 * FindDefaultConversion
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.
236 Oid FindDefaultConversion(Oid name_space, int4 for_encoding, int4 to_encoding)
240 Form_pg_conversion body;
241 Oid proc = InvalidOid;
244 /* Check we have usage rights in target namespace */
245 if (pg_namespace_aclcheck(name_space, GetUserId(), ACL_USAGE) != ACLCHECK_OK)
248 catlist = SearchSysCacheList(CONDEFAULT, 3,
249 ObjectIdGetDatum(name_space),
250 Int32GetDatum(for_encoding),
251 Int32GetDatum(to_encoding),
254 for (i = 0; i < catlist->n_members; i++)
256 tuple = &catlist->members[i]->tuple;
257 body = (Form_pg_conversion)GETSTRUCT(tuple);
258 if (body->condefault == TRUE)
260 proc = body->conproc;
264 ReleaseSysCacheList(catlist);
269 * FindConversionByName
271 * Find conversion by namespace and conversion name.
272 * Returns conversion oid.
275 Oid FindConversion(const char *conname, Oid connamespace)
282 /* search pg_conversion by connamespace and conversion name */
283 tuple = SearchSysCache(CONNAMESP,
284 PointerGetDatum(conname),
285 ObjectIdGetDatum(connamespace),
288 if (!HeapTupleIsValid(tuple))
290 procoid = ((Form_pg_conversion)GETSTRUCT(tuple))->conproc;
291 conoid = HeapTupleGetOid(tuple);
293 ReleaseSysCache(tuple);
295 /* Check we have execute rights for the function */
296 aclresult = pg_proc_aclcheck(procoid, GetUserId(), ACL_EXECUTE);
297 if (aclresult != ACLCHECK_OK)
304 * Execute SQL99's CONVERT function.
306 * CONVERT <left paren> <character value expression>
307 * USING <form-of-use conversion name> <right paren>
309 * TEXT convert3(TEXT string, OID conversion_oid);
312 pg_convert3(PG_FUNCTION_ARGS)
314 text *string = PG_GETARG_TEXT_P(0);
315 Oid convoid = PG_GETARG_OID(1);
317 Form_pg_conversion body;
320 unsigned char *result;
323 if (!OidIsValid(convoid))
324 elog(ERROR, "Conversion does not exist");
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);
332 tuple = SearchSysCache(CONOID,
333 ObjectIdGetDatum(convoid),
335 if (!HeapTupleIsValid(tuple))
336 elog(ERROR, "Conversion %u search from syscache failed", convoid);
338 result = palloc(len * 4 + 1);
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),
348 ReleaseSysCache(tuple);
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);
361 /* free memory if allocated by the toaster */
362 PG_FREE_IF_COPY(string, 0);
364 PG_RETURN_TEXT_P(retval);