Fix oversight in previous error-reporting patch; mustn't pfree path string
[PostgreSQL.git] / src / backend / catalog / pg_conversion.c
bloba90905782ad22bfc9ac6a9f4d2f063ea5a08ae72
1 /*-------------------------------------------------------------------------
3 * pg_conversion.c
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
10 * IDENTIFICATION
11 * $PostgreSQL$
13 *-------------------------------------------------------------------------
15 #include "postgres.h"
17 #include "access/heapam.h"
18 #include "access/sysattr.h"
19 #include "catalog/dependency.h"
20 #include "catalog/indexing.h"
21 #include "catalog/pg_conversion.h"
22 #include "catalog/pg_conversion_fn.h"
23 #include "catalog/pg_namespace.h"
24 #include "catalog/pg_proc.h"
25 #include "mb/pg_wchar.h"
26 #include "miscadmin.h"
27 #include "utils/acl.h"
28 #include "utils/builtins.h"
29 #include "utils/fmgroids.h"
30 #include "utils/rel.h"
31 #include "utils/syscache.h"
32 #include "utils/tqual.h"
35 * ConversionCreate
37 * Add a new tuple to pg_conversion.
39 Oid
40 ConversionCreate(const char *conname, Oid connamespace,
41 Oid conowner,
42 int32 conforencoding, int32 contoencoding,
43 Oid conproc, bool def)
45 int i;
46 Relation rel;
47 TupleDesc tupDesc;
48 HeapTuple tup;
49 bool nulls[Natts_pg_conversion];
50 Datum values[Natts_pg_conversion];
51 NameData cname;
52 Oid oid;
53 ObjectAddress myself,
54 referenced;
56 /* sanity checks */
57 if (!conname)
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),
64 0, 0))
65 ereport(ERROR,
66 (errcode(ERRCODE_DUPLICATE_OBJECT),
67 errmsg("conversion \"%s\" already exists", conname)));
69 if (def)
72 * make sure there is no existing default <for encoding><to encoding>
73 * pair in this name space
75 if (FindDefaultConversion(connamespace,
76 conforencoding,
77 contoencoding))
78 ereport(ERROR,
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++)
92 nulls[i] = false;
93 values[i] = (Datum) NULL;
96 /* form a tuple */
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_form_tuple(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),
133 conowner);
135 heap_freetuple(tup);
136 heap_close(rel, RowExclusiveLock);
138 return oid;
142 * RemoveConversionById
144 * Remove a tuple from pg_conversion by Oid. This function is solely
145 * called inside catalog/dependency.c
147 void
148 RemoveConversionById(Oid conversionOid)
150 Relation rel;
151 HeapTuple tuple;
152 HeapScanDesc scan;
153 ScanKeyData scanKeyData;
155 ScanKeyInit(&scanKeyData,
156 ObjectIdAttributeNumber,
157 BTEqualStrategyNumber, F_OIDEQ,
158 ObjectIdGetDatum(conversionOid));
160 /* open pg_conversion */
161 rel = heap_open(ConversionRelationId, RowExclusiveLock);
163 scan = heap_beginscan(rel, SnapshotNow,
164 1, &scanKeyData);
166 /* search for the target tuple */
167 if (HeapTupleIsValid(tuple = heap_getnext(scan, ForwardScanDirection)))
168 simple_heap_delete(rel, &tuple->t_self);
169 else
170 elog(ERROR, "could not find tuple for conversion %u", conversionOid);
171 heap_endscan(scan);
172 heap_close(rel, RowExclusiveLock);
176 * FindDefaultConversion
178 * Find "default" conversion proc by for_encoding and to_encoding in the
179 * given namespace.
181 * If found, returns the procedure's oid, otherwise InvalidOid. Note that
182 * you get the procedure's OID not the conversion's OID!
185 FindDefaultConversion(Oid name_space, int32 for_encoding, int32 to_encoding)
187 CatCList *catlist;
188 HeapTuple tuple;
189 Form_pg_conversion body;
190 Oid proc = InvalidOid;
191 int i;
193 catlist = SearchSysCacheList(CONDEFAULT, 3,
194 ObjectIdGetDatum(name_space),
195 Int32GetDatum(for_encoding),
196 Int32GetDatum(to_encoding),
199 for (i = 0; i < catlist->n_members; i++)
201 tuple = &catlist->members[i]->tuple;
202 body = (Form_pg_conversion) GETSTRUCT(tuple);
203 if (body->condefault)
205 proc = body->conproc;
206 break;
209 ReleaseSysCacheList(catlist);
210 return proc;
214 * FindConversion
216 * Find conversion by namespace and conversion name.
217 * Returns conversion OID.
220 FindConversion(const char *conname, Oid connamespace)
222 HeapTuple tuple;
223 Oid procoid;
224 Oid conoid;
225 AclResult aclresult;
227 /* search pg_conversion by connamespace and conversion name */
228 tuple = SearchSysCache(CONNAMENSP,
229 PointerGetDatum(conname),
230 ObjectIdGetDatum(connamespace),
231 0, 0);
232 if (!HeapTupleIsValid(tuple))
233 return InvalidOid;
235 procoid = ((Form_pg_conversion) GETSTRUCT(tuple))->conproc;
236 conoid = HeapTupleGetOid(tuple);
238 ReleaseSysCache(tuple);
240 /* Check we have execute rights for the function */
241 aclresult = pg_proc_aclcheck(procoid, GetUserId(), ACL_EXECUTE);
242 if (aclresult != ACLCHECK_OK)
243 return InvalidOid;
245 return conoid;