postgresql/src/backend/catalog/pg_conversion.c
Tom Lane ab02896510 Provide CatalogTupleDelete() as a wrapper around simple_heap_delete().
This extends the work done in commit 2f5c9d9c9 to provide a more nearly
complete abstraction layer hiding the details of index updating for catalog
changes.  That commit only invented abstractions for catalog inserts and
updates, leaving nearby code for catalog deletes still calling the
heap-level routines directly.  That seems rather ugly from here, and it
does little to help if we ever want to shift to a storage system in which
indexing work is needed at delete time.

Hence, create a wrapper function CatalogTupleDelete(), and replace calls
of simple_heap_delete() on catalog tuples with it.  There are now very
few direct calls of [simple_]heap_delete remaining in the tree.

Discussion: https://postgr.es/m/462.1485902736@sss.pgh.pa.us
2017-02-01 16:13:30 -05:00

211 lines
5.6 KiB
C

/*-------------------------------------------------------------------------
*
* pg_conversion.c
* routines to support manipulation of the pg_conversion relation
*
* Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* src/backend/catalog/pg_conversion.c
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/heapam.h"
#include "access/htup_details.h"
#include "access/sysattr.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_conversion.h"
#include "catalog/pg_conversion_fn.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_proc.h"
#include "mb/pg_wchar.h"
#include "utils/builtins.h"
#include "utils/catcache.h"
#include "utils/fmgroids.h"
#include "utils/rel.h"
#include "utils/syscache.h"
#include "utils/tqual.h"
/*
* ConversionCreate
*
* Add a new tuple to pg_conversion.
*/
ObjectAddress
ConversionCreate(const char *conname, Oid connamespace,
Oid conowner,
int32 conforencoding, int32 contoencoding,
Oid conproc, bool def)
{
int i;
Relation rel;
TupleDesc tupDesc;
HeapTuple tup;
bool nulls[Natts_pg_conversion];
Datum values[Natts_pg_conversion];
NameData cname;
ObjectAddress myself,
referenced;
/* sanity checks */
if (!conname)
elog(ERROR, "no conversion name supplied");
/* make sure there is no existing conversion of same name */
if (SearchSysCacheExists2(CONNAMENSP,
PointerGetDatum(conname),
ObjectIdGetDatum(connamespace)))
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("conversion \"%s\" already exists", conname)));
if (def)
{
/*
* make sure there is no existing default <for encoding><to encoding>
* pair in this name space
*/
if (FindDefaultConversion(connamespace,
conforencoding,
contoencoding))
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("default conversion for %s to %s already exists",
pg_encoding_to_char(conforencoding),
pg_encoding_to_char(contoencoding))));
}
/* open pg_conversion */
rel = heap_open(ConversionRelationId, RowExclusiveLock);
tupDesc = rel->rd_att;
/* initialize nulls and values */
for (i = 0; i < Natts_pg_conversion; i++)
{
nulls[i] = false;
values[i] = (Datum) NULL;
}
/* form a tuple */
namestrcpy(&cname, conname);
values[Anum_pg_conversion_conname - 1] = NameGetDatum(&cname);
values[Anum_pg_conversion_connamespace - 1] = ObjectIdGetDatum(connamespace);
values[Anum_pg_conversion_conowner - 1] = ObjectIdGetDatum(conowner);
values[Anum_pg_conversion_conforencoding - 1] = Int32GetDatum(conforencoding);
values[Anum_pg_conversion_contoencoding - 1] = Int32GetDatum(contoencoding);
values[Anum_pg_conversion_conproc - 1] = ObjectIdGetDatum(conproc);
values[Anum_pg_conversion_condefault - 1] = BoolGetDatum(def);
tup = heap_form_tuple(tupDesc, values, nulls);
/* insert a new tuple */
CatalogTupleInsert(rel, tup);
myself.classId = ConversionRelationId;
myself.objectId = HeapTupleGetOid(tup);
myself.objectSubId = 0;
/* create dependency on conversion procedure */
referenced.classId = ProcedureRelationId;
referenced.objectId = conproc;
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
/* create dependency on namespace */
referenced.classId = NamespaceRelationId;
referenced.objectId = connamespace;
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
/* create dependency on owner */
recordDependencyOnOwner(ConversionRelationId, HeapTupleGetOid(tup),
conowner);
/* dependency on extension */
recordDependencyOnCurrentExtension(&myself, false);
/* Post creation hook for new conversion */
InvokeObjectPostCreateHook(ConversionRelationId, HeapTupleGetOid(tup), 0);
heap_freetuple(tup);
heap_close(rel, RowExclusiveLock);
return myself;
}
/*
* RemoveConversionById
*
* Remove a tuple from pg_conversion by Oid. This function is solely
* called inside catalog/dependency.c
*/
void
RemoveConversionById(Oid conversionOid)
{
Relation rel;
HeapTuple tuple;
HeapScanDesc scan;
ScanKeyData scanKeyData;
ScanKeyInit(&scanKeyData,
ObjectIdAttributeNumber,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(conversionOid));
/* open pg_conversion */
rel = heap_open(ConversionRelationId, RowExclusiveLock);
scan = heap_beginscan_catalog(rel, 1, &scanKeyData);
/* search for the target tuple */
if (HeapTupleIsValid(tuple = heap_getnext(scan, ForwardScanDirection)))
CatalogTupleDelete(rel, &tuple->t_self);
else
elog(ERROR, "could not find tuple for conversion %u", conversionOid);
heap_endscan(scan);
heap_close(rel, RowExclusiveLock);
}
/*
* FindDefaultConversion
*
* Find "default" conversion proc by for_encoding and to_encoding in the
* given namespace.
*
* If found, returns the procedure's oid, otherwise InvalidOid. Note that
* you get the procedure's OID not the conversion's OID!
*/
Oid
FindDefaultConversion(Oid name_space, int32 for_encoding, int32 to_encoding)
{
CatCList *catlist;
HeapTuple tuple;
Form_pg_conversion body;
Oid proc = InvalidOid;
int i;
catlist = SearchSysCacheList3(CONDEFAULT,
ObjectIdGetDatum(name_space),
Int32GetDatum(for_encoding),
Int32GetDatum(to_encoding));
for (i = 0; i < catlist->n_members; i++)
{
tuple = &catlist->members[i]->tuple;
body = (Form_pg_conversion) GETSTRUCT(tuple);
if (body->condefault)
{
proc = body->conproc;
break;
}
}
ReleaseSysCacheList(catlist);
return proc;
}