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
13 *-------------------------------------------------------------------------
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"
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 bool 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_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
),
136 heap_close(rel
, RowExclusiveLock
);
142 * RemoveConversionById
144 * Remove a tuple from pg_conversion by Oid. This function is solely
145 * called inside catalog/dependency.c
148 RemoveConversionById(Oid conversionOid
)
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
,
166 /* search for the target tuple */
167 if (HeapTupleIsValid(tuple
= heap_getnext(scan
, ForwardScanDirection
)))
168 simple_heap_delete(rel
, &tuple
->t_self
);
170 elog(ERROR
, "could not find tuple for conversion %u", conversionOid
);
172 heap_close(rel
, RowExclusiveLock
);
176 * FindDefaultConversion
178 * Find "default" conversion proc by for_encoding and to_encoding in the
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
)
189 Form_pg_conversion body
;
190 Oid proc
= InvalidOid
;
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
;
209 ReleaseSysCacheList(catlist
);
216 * Find conversion by namespace and conversion name.
217 * Returns conversion OID.
220 FindConversion(const char *conname
, Oid connamespace
)
227 /* search pg_conversion by connamespace and conversion name */
228 tuple
= SearchSysCache(CONNAMENSP
,
229 PointerGetDatum(conname
),
230 ObjectIdGetDatum(connamespace
),
232 if (!HeapTupleIsValid(tuple
))
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
)