Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * pg_conversion.c
4 : * routines to support manipulation of the pg_conversion relation
5 : *
6 : * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
7 : * Portions Copyright (c) 1994, Regents of the University of California
8 : *
9 : *
10 : * IDENTIFICATION
11 : * src/backend/catalog/pg_conversion.c
12 : *
13 : *-------------------------------------------------------------------------
14 : */
15 : #include "postgres.h"
16 :
17 : #include "access/heapam.h"
18 : #include "access/htup_details.h"
19 : #include "access/sysattr.h"
20 : #include "catalog/dependency.h"
21 : #include "catalog/indexing.h"
22 : #include "catalog/objectaccess.h"
23 : #include "catalog/pg_conversion.h"
24 : #include "catalog/pg_conversion_fn.h"
25 : #include "catalog/pg_namespace.h"
26 : #include "catalog/pg_proc.h"
27 : #include "mb/pg_wchar.h"
28 : #include "utils/builtins.h"
29 : #include "utils/catcache.h"
30 : #include "utils/fmgroids.h"
31 : #include "utils/rel.h"
32 : #include "utils/syscache.h"
33 : #include "utils/tqual.h"
34 :
35 : /*
36 : * ConversionCreate
37 : *
38 : * Add a new tuple to pg_conversion.
39 : */
40 : ObjectAddress
41 142 : ConversionCreate(const char *conname, Oid connamespace,
42 : Oid conowner,
43 : int32 conforencoding, int32 contoencoding,
44 : Oid conproc, bool def)
45 : {
46 : int i;
47 : Relation rel;
48 : TupleDesc tupDesc;
49 : HeapTuple tup;
50 : bool nulls[Natts_pg_conversion];
51 : Datum values[Natts_pg_conversion];
52 : NameData cname;
53 : ObjectAddress myself,
54 : referenced;
55 :
56 : /* sanity checks */
57 142 : if (!conname)
58 0 : elog(ERROR, "no conversion name supplied");
59 :
60 : /* make sure there is no existing conversion of same name */
61 142 : if (SearchSysCacheExists2(CONNAMENSP,
62 : PointerGetDatum(conname),
63 : ObjectIdGetDatum(connamespace)))
64 1 : ereport(ERROR,
65 : (errcode(ERRCODE_DUPLICATE_OBJECT),
66 : errmsg("conversion \"%s\" already exists", conname)));
67 :
68 141 : if (def)
69 : {
70 : /*
71 : * make sure there is no existing default <for encoding><to encoding>
72 : * pair in this name space
73 : */
74 134 : if (FindDefaultConversion(connamespace,
75 : conforencoding,
76 : contoencoding))
77 1 : ereport(ERROR,
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))));
82 : }
83 :
84 : /* open pg_conversion */
85 140 : rel = heap_open(ConversionRelationId, RowExclusiveLock);
86 140 : tupDesc = rel->rd_att;
87 :
88 : /* initialize nulls and values */
89 1120 : for (i = 0; i < Natts_pg_conversion; i++)
90 : {
91 980 : nulls[i] = false;
92 980 : values[i] = (Datum) NULL;
93 : }
94 :
95 : /* form a tuple */
96 140 : namestrcpy(&cname, conname);
97 140 : values[Anum_pg_conversion_conname - 1] = NameGetDatum(&cname);
98 140 : values[Anum_pg_conversion_connamespace - 1] = ObjectIdGetDatum(connamespace);
99 140 : values[Anum_pg_conversion_conowner - 1] = ObjectIdGetDatum(conowner);
100 140 : values[Anum_pg_conversion_conforencoding - 1] = Int32GetDatum(conforencoding);
101 140 : values[Anum_pg_conversion_contoencoding - 1] = Int32GetDatum(contoencoding);
102 140 : values[Anum_pg_conversion_conproc - 1] = ObjectIdGetDatum(conproc);
103 140 : values[Anum_pg_conversion_condefault - 1] = BoolGetDatum(def);
104 :
105 140 : tup = heap_form_tuple(tupDesc, values, nulls);
106 :
107 : /* insert a new tuple */
108 140 : CatalogTupleInsert(rel, tup);
109 :
110 140 : myself.classId = ConversionRelationId;
111 140 : myself.objectId = HeapTupleGetOid(tup);
112 140 : myself.objectSubId = 0;
113 :
114 : /* create dependency on conversion procedure */
115 140 : referenced.classId = ProcedureRelationId;
116 140 : referenced.objectId = conproc;
117 140 : referenced.objectSubId = 0;
118 140 : recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
119 :
120 : /* create dependency on namespace */
121 140 : referenced.classId = NamespaceRelationId;
122 140 : referenced.objectId = connamespace;
123 140 : referenced.objectSubId = 0;
124 140 : recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
125 :
126 : /* create dependency on owner */
127 140 : recordDependencyOnOwner(ConversionRelationId, HeapTupleGetOid(tup),
128 : conowner);
129 :
130 : /* dependency on extension */
131 140 : recordDependencyOnCurrentExtension(&myself, false);
132 :
133 : /* Post creation hook for new conversion */
134 140 : InvokeObjectPostCreateHook(ConversionRelationId, HeapTupleGetOid(tup), 0);
135 :
136 140 : heap_freetuple(tup);
137 140 : heap_close(rel, RowExclusiveLock);
138 :
139 140 : return myself;
140 : }
141 :
142 : /*
143 : * RemoveConversionById
144 : *
145 : * Remove a tuple from pg_conversion by Oid. This function is solely
146 : * called inside catalog/dependency.c
147 : */
148 : void
149 8 : RemoveConversionById(Oid conversionOid)
150 : {
151 : Relation rel;
152 : HeapTuple tuple;
153 : HeapScanDesc scan;
154 : ScanKeyData scanKeyData;
155 :
156 8 : ScanKeyInit(&scanKeyData,
157 : ObjectIdAttributeNumber,
158 : BTEqualStrategyNumber, F_OIDEQ,
159 : ObjectIdGetDatum(conversionOid));
160 :
161 : /* open pg_conversion */
162 8 : rel = heap_open(ConversionRelationId, RowExclusiveLock);
163 :
164 8 : scan = heap_beginscan_catalog(rel, 1, &scanKeyData);
165 :
166 : /* search for the target tuple */
167 8 : if (HeapTupleIsValid(tuple = heap_getnext(scan, ForwardScanDirection)))
168 8 : CatalogTupleDelete(rel, &tuple->t_self);
169 : else
170 0 : elog(ERROR, "could not find tuple for conversion %u", conversionOid);
171 8 : heap_endscan(scan);
172 8 : heap_close(rel, RowExclusiveLock);
173 8 : }
174 :
175 : /*
176 : * FindDefaultConversion
177 : *
178 : * Find "default" conversion proc by for_encoding and to_encoding in the
179 : * given namespace.
180 : *
181 : * If found, returns the procedure's oid, otherwise InvalidOid. Note that
182 : * you get the procedure's OID not the conversion's OID!
183 : */
184 : Oid
185 262 : FindDefaultConversion(Oid name_space, int32 for_encoding, int32 to_encoding)
186 : {
187 : CatCList *catlist;
188 : HeapTuple tuple;
189 : Form_pg_conversion body;
190 262 : Oid proc = InvalidOid;
191 : int i;
192 :
193 262 : catlist = SearchSysCacheList3(CONDEFAULT,
194 : ObjectIdGetDatum(name_space),
195 : Int32GetDatum(for_encoding),
196 : Int32GetDatum(to_encoding));
197 :
198 264 : for (i = 0; i < catlist->n_members; i++)
199 : {
200 131 : tuple = &catlist->members[i]->tuple;
201 131 : body = (Form_pg_conversion) GETSTRUCT(tuple);
202 131 : if (body->condefault)
203 : {
204 129 : proc = body->conproc;
205 129 : break;
206 : }
207 : }
208 262 : ReleaseSysCacheList(catlist);
209 262 : return proc;
210 : }
|