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-2023, 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 "access/tableam.h"
21 : #include "catalog/catalog.h"
22 : #include "catalog/dependency.h"
23 : #include "catalog/indexing.h"
24 : #include "catalog/objectaccess.h"
25 : #include "catalog/pg_conversion.h"
26 : #include "catalog/pg_namespace.h"
27 : #include "catalog/pg_proc.h"
28 : #include "mb/pg_wchar.h"
29 : #include "utils/builtins.h"
30 : #include "utils/catcache.h"
31 : #include "utils/fmgroids.h"
32 : #include "utils/rel.h"
33 : #include "utils/syscache.h"
34 :
35 : /*
36 : * ConversionCreate
37 : *
38 : * Add a new tuple to pg_conversion.
39 : */
40 : ObjectAddress
41 64 : 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 : Oid oid;
51 : bool nulls[Natts_pg_conversion];
52 : Datum values[Natts_pg_conversion];
53 : NameData cname;
54 : ObjectAddress myself,
55 : referenced;
56 :
57 : /* sanity checks */
58 64 : if (!conname)
59 0 : elog(ERROR, "no conversion name supplied");
60 :
61 : /* make sure there is no existing conversion of same name */
62 64 : if (SearchSysCacheExists2(CONNAMENSP,
63 : PointerGetDatum(conname),
64 : ObjectIdGetDatum(connamespace)))
65 6 : ereport(ERROR,
66 : (errcode(ERRCODE_DUPLICATE_OBJECT),
67 : errmsg("conversion \"%s\" already exists", conname)));
68 :
69 58 : if (def)
70 : {
71 : /*
72 : * make sure there is no existing default <for encoding><to encoding>
73 : * pair in this name space
74 : */
75 14 : if (FindDefaultConversion(connamespace,
76 : conforencoding,
77 : contoencoding))
78 6 : 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))));
83 : }
84 :
85 : /* open pg_conversion */
86 52 : rel = table_open(ConversionRelationId, RowExclusiveLock);
87 52 : tupDesc = rel->rd_att;
88 :
89 : /* initialize nulls and values */
90 468 : for (i = 0; i < Natts_pg_conversion; i++)
91 : {
92 416 : nulls[i] = false;
93 416 : values[i] = (Datum) NULL;
94 : }
95 :
96 : /* form a tuple */
97 52 : namestrcpy(&cname, conname);
98 52 : oid = GetNewOidWithIndex(rel, ConversionOidIndexId,
99 : Anum_pg_conversion_oid);
100 52 : values[Anum_pg_conversion_oid - 1] = ObjectIdGetDatum(oid);
101 52 : values[Anum_pg_conversion_conname - 1] = NameGetDatum(&cname);
102 52 : values[Anum_pg_conversion_connamespace - 1] = ObjectIdGetDatum(connamespace);
103 52 : values[Anum_pg_conversion_conowner - 1] = ObjectIdGetDatum(conowner);
104 52 : values[Anum_pg_conversion_conforencoding - 1] = Int32GetDatum(conforencoding);
105 52 : values[Anum_pg_conversion_contoencoding - 1] = Int32GetDatum(contoencoding);
106 52 : values[Anum_pg_conversion_conproc - 1] = ObjectIdGetDatum(conproc);
107 52 : values[Anum_pg_conversion_condefault - 1] = BoolGetDatum(def);
108 :
109 52 : tup = heap_form_tuple(tupDesc, values, nulls);
110 :
111 : /* insert a new tuple */
112 52 : CatalogTupleInsert(rel, tup);
113 :
114 52 : myself.classId = ConversionRelationId;
115 52 : myself.objectId = oid;
116 52 : myself.objectSubId = 0;
117 :
118 : /* create dependency on conversion procedure */
119 52 : referenced.classId = ProcedureRelationId;
120 52 : referenced.objectId = conproc;
121 52 : referenced.objectSubId = 0;
122 52 : recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
123 :
124 : /* create dependency on namespace */
125 52 : referenced.classId = NamespaceRelationId;
126 52 : referenced.objectId = connamespace;
127 52 : referenced.objectSubId = 0;
128 52 : recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
129 :
130 : /* create dependency on owner */
131 52 : recordDependencyOnOwner(ConversionRelationId, oid, conowner);
132 :
133 : /* dependency on extension */
134 52 : recordDependencyOnCurrentExtension(&myself, false);
135 :
136 : /* Post creation hook for new conversion */
137 52 : InvokeObjectPostCreateHook(ConversionRelationId, oid, 0);
138 :
139 52 : heap_freetuple(tup);
140 52 : table_close(rel, RowExclusiveLock);
141 :
142 52 : return myself;
143 : }
144 :
145 : /*
146 : * FindDefaultConversion
147 : *
148 : * Find "default" conversion proc by for_encoding and to_encoding in the
149 : * given namespace.
150 : *
151 : * If found, returns the procedure's oid, otherwise InvalidOid. Note that
152 : * you get the procedure's OID not the conversion's OID!
153 : */
154 : Oid
155 6704 : FindDefaultConversion(Oid name_space, int32 for_encoding, int32 to_encoding)
156 : {
157 : CatCList *catlist;
158 : HeapTuple tuple;
159 : Form_pg_conversion body;
160 6704 : Oid proc = InvalidOid;
161 : int i;
162 :
163 6704 : catlist = SearchSysCacheList3(CONDEFAULT,
164 : ObjectIdGetDatum(name_space),
165 : Int32GetDatum(for_encoding),
166 : Int32GetDatum(to_encoding));
167 :
168 6716 : for (i = 0; i < catlist->n_members; i++)
169 : {
170 6708 : tuple = &catlist->members[i]->tuple;
171 6708 : body = (Form_pg_conversion) GETSTRUCT(tuple);
172 6708 : if (body->condefault)
173 : {
174 6696 : proc = body->conproc;
175 6696 : break;
176 : }
177 : }
178 6704 : ReleaseSysCacheList(catlist);
179 6704 : return proc;
180 : }
|