diff options
Diffstat (limited to 'src/backend/catalog/pg_conversion.c')
-rw-r--r-- | src/backend/catalog/pg_conversion.c | 180 |
1 files changed, 180 insertions, 0 deletions
diff --git a/src/backend/catalog/pg_conversion.c b/src/backend/catalog/pg_conversion.c new file mode 100644 index 0000000..02ac7c4 --- /dev/null +++ b/src/backend/catalog/pg_conversion.c @@ -0,0 +1,180 @@ +/*------------------------------------------------------------------------- + * + * pg_conversion.c + * routines to support manipulation of the pg_conversion relation + * + * Portions Copyright (c) 1996-2021, 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 "access/tableam.h" +#include "catalog/catalog.h" +#include "catalog/dependency.h" +#include "catalog/indexing.h" +#include "catalog/objectaccess.h" +#include "catalog/pg_conversion.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" + +/* + * 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; + Oid oid; + 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 = table_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); + oid = GetNewOidWithIndex(rel, ConversionOidIndexId, + Anum_pg_conversion_oid); + values[Anum_pg_conversion_oid - 1] = ObjectIdGetDatum(oid); + 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 = oid; + 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, oid, conowner); + + /* dependency on extension */ + recordDependencyOnCurrentExtension(&myself, false); + + /* Post creation hook for new conversion */ + InvokeObjectPostCreateHook(ConversionRelationId, oid, 0); + + heap_freetuple(tup); + table_close(rel, RowExclusiveLock); + + return myself; +} + +/* + * 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; +} |