summaryrefslogtreecommitdiffstats
path: root/src/backend/catalog/pg_conversion.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/catalog/pg_conversion.c')
-rw-r--r--src/backend/catalog/pg_conversion.c180
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;
+}