1 /*-------------------------------------------------------------------------
4 * routines to support manipulation of the pg_conversion relation
6 * Portions Copyright (c) 1996-2008, 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.43 2008/05/12 00:00:47 alvherre Exp $
13 *-------------------------------------------------------------------------
17 #include "access/heapam.h"
18 #include "access/sysattr.h"
19 #include "catalog/dependency.h"
20 #include "catalog/indexing.h"
21 #include "catalog/namespace.h"
22 #include "catalog/pg_conversion.h"
23 #include "catalog/pg_conversion_fn.h"
24 #include "catalog/pg_namespace.h"
25 #include "catalog/pg_proc.h"
26 #include "mb/pg_wchar.h"
27 #include "miscadmin.h"
28 #include "utils/acl.h"
29 #include "utils/builtins.h"
30 #include "utils/fmgroids.h"
31 #include "utils/syscache.h"
32 #include "utils/tqual.h"
37 * Add a new tuple to pg_conversion.
40 ConversionCreate(const char *conname, Oid connamespace,
42 int32 conforencoding, int32 contoencoding,
43 Oid conproc, bool def)
49 char nulls[Natts_pg_conversion];
50 Datum values[Natts_pg_conversion];
58 elog(ERROR, "no conversion name supplied");
60 /* make sure there is no existing conversion of same name */
61 if (SearchSysCacheExists(CONNAMENSP,
62 PointerGetDatum(conname),
63 ObjectIdGetDatum(connamespace),
66 (errcode(ERRCODE_DUPLICATE_OBJECT),
67 errmsg("conversion \"%s\" already exists", conname)));
72 * make sure there is no existing default <for encoding><to encoding>
73 * pair in this name space
75 if (FindDefaultConversion(connamespace,
79 (errcode(ERRCODE_DUPLICATE_OBJECT),
80 errmsg("default conversion for %s to %s already exists",
81 pg_encoding_to_char(conforencoding),
82 pg_encoding_to_char(contoencoding))));
85 /* open pg_conversion */
86 rel = heap_open(ConversionRelationId, RowExclusiveLock);
87 tupDesc = rel->rd_att;
89 /* initialize nulls and values */
90 for (i = 0; i < Natts_pg_conversion; i++)
93 values[i] = (Datum) NULL;
97 namestrcpy(&cname, conname);
98 values[Anum_pg_conversion_conname - 1] = NameGetDatum(&cname);
99 values[Anum_pg_conversion_connamespace - 1] = ObjectIdGetDatum(connamespace);
100 values[Anum_pg_conversion_conowner - 1] = ObjectIdGetDatum(conowner);
101 values[Anum_pg_conversion_conforencoding - 1] = Int32GetDatum(conforencoding);
102 values[Anum_pg_conversion_contoencoding - 1] = Int32GetDatum(contoencoding);
103 values[Anum_pg_conversion_conproc - 1] = ObjectIdGetDatum(conproc);
104 values[Anum_pg_conversion_condefault - 1] = BoolGetDatum(def);
106 tup = heap_formtuple(tupDesc, values, nulls);
108 /* insert a new tuple */
109 oid = simple_heap_insert(rel, tup);
110 Assert(OidIsValid(oid));
112 /* update the index if any */
113 CatalogUpdateIndexes(rel, tup);
115 myself.classId = ConversionRelationId;
116 myself.objectId = HeapTupleGetOid(tup);
117 myself.objectSubId = 0;
119 /* create dependency on conversion procedure */
120 referenced.classId = ProcedureRelationId;
121 referenced.objectId = conproc;
122 referenced.objectSubId = 0;
123 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
125 /* create dependency on namespace */
126 referenced.classId = NamespaceRelationId;
127 referenced.objectId = connamespace;
128 referenced.objectSubId = 0;
129 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
131 /* create dependency on owner */
132 recordDependencyOnOwner(ConversionRelationId, HeapTupleGetOid(tup),
136 heap_close(rel, RowExclusiveLock);
144 * Drop a conversion after doing permission checks.
147 ConversionDrop(Oid conversionOid, DropBehavior behavior)
150 ObjectAddress object;
152 tuple = SearchSysCache(CONVOID,
153 ObjectIdGetDatum(conversionOid),
155 if (!HeapTupleIsValid(tuple))
156 elog(ERROR, "cache lookup failed for conversion %u", conversionOid);
159 ((Form_pg_conversion) GETSTRUCT(tuple))->conowner != GetUserId())
160 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CONVERSION,
161 NameStr(((Form_pg_conversion) GETSTRUCT(tuple))->conname));
163 ReleaseSysCache(tuple);
168 object.classId = ConversionRelationId;
169 object.objectId = conversionOid;
170 object.objectSubId = 0;
172 performDeletion(&object, behavior);
176 * RemoveConversionById
178 * Remove a tuple from pg_conversion by Oid. This function is solely
179 * called inside catalog/dependency.c
182 RemoveConversionById(Oid conversionOid)
187 ScanKeyData scanKeyData;
189 ScanKeyInit(&scanKeyData,
190 ObjectIdAttributeNumber,
191 BTEqualStrategyNumber, F_OIDEQ,
192 ObjectIdGetDatum(conversionOid));
194 /* open pg_conversion */
195 rel = heap_open(ConversionRelationId, RowExclusiveLock);
197 scan = heap_beginscan(rel, SnapshotNow,
200 /* search for the target tuple */
201 if (HeapTupleIsValid(tuple = heap_getnext(scan, ForwardScanDirection)))
202 simple_heap_delete(rel, &tuple->t_self);
204 elog(ERROR, "could not find tuple for conversion %u", conversionOid);
206 heap_close(rel, RowExclusiveLock);
210 * FindDefaultConversion
212 * Find "default" conversion proc by for_encoding and to_encoding in the
215 * If found, returns the procedure's oid, otherwise InvalidOid. Note that
216 * you get the procedure's OID not the conversion's OID!
219 FindDefaultConversion(Oid name_space, int32 for_encoding, int32 to_encoding)
223 Form_pg_conversion body;
224 Oid proc = InvalidOid;
227 catlist = SearchSysCacheList(CONDEFAULT, 3,
228 ObjectIdGetDatum(name_space),
229 Int32GetDatum(for_encoding),
230 Int32GetDatum(to_encoding),
233 for (i = 0; i < catlist->n_members; i++)
235 tuple = &catlist->members[i]->tuple;
236 body = (Form_pg_conversion) GETSTRUCT(tuple);
237 if (body->condefault)
239 proc = body->conproc;
243 ReleaseSysCacheList(catlist);
250 * Find conversion by namespace and conversion name.
251 * Returns conversion OID.
254 FindConversion(const char *conname, Oid connamespace)
261 /* search pg_conversion by connamespace and conversion name */
262 tuple = SearchSysCache(CONNAMENSP,
263 PointerGetDatum(conname),
264 ObjectIdGetDatum(connamespace),
266 if (!HeapTupleIsValid(tuple))
269 procoid = ((Form_pg_conversion) GETSTRUCT(tuple))->conproc;
270 conoid = HeapTupleGetOid(tuple);
272 ReleaseSysCache(tuple);
274 /* Check we have execute rights for the function */
275 aclresult = pg_proc_aclcheck(procoid, GetUserId(), ACL_EXECUTE);
276 if (aclresult != ACLCHECK_OK)