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