summaryrefslogtreecommitdiff
path: root/src/backend/catalog/pg_cast.c
blob: 1fee83c71bf2b4875ade6f2c8cd179b5ef523c8f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
/*-------------------------------------------------------------------------
 *
 * pg_cast.c
 *	  routines to support manipulation of the pg_cast relation
 *
 * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
 *	  src/backend/catalog/pg_cast.c
 *
 *-------------------------------------------------------------------------
 */
#include "postgres.h"

#include "access/htup_details.h"
#include "access/table.h"
#include "catalog/catalog.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_cast.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "utils/builtins.h"
#include "utils/rel.h"
#include "utils/syscache.h"

/*
 * ----------------------------------------------------------------
 *		CastCreate
 *
 * Forms and inserts catalog tuples for a new cast being created.
 * Caller must have already checked privileges, and done consistency
 * checks on the given datatypes and cast function (if applicable).
 *
 * Since we allow binary coercibility of the datatypes to the cast
 * function's input and result, there could be one or two WITHOUT FUNCTION
 * casts that this one depends on.  We don't record that explicitly
 * in pg_cast, but we still need to make dependencies on those casts.
 *
 * 'behavior' indicates the types of the dependencies that the new
 * cast will have on its input and output types, the cast function,
 * and the other casts if any.
 * ----------------------------------------------------------------
 */
ObjectAddress
CastCreate(Oid sourcetypeid, Oid targettypeid,
		   Oid funcid, Oid incastid, Oid outcastid,
		   char castcontext, char castmethod, DependencyType behavior)
{
	Relation	relation;
	HeapTuple	tuple;
	Oid			castid;
	Datum		values[Natts_pg_cast];
	bool		nulls[Natts_pg_cast] = {0};
	ObjectAddress myself,
				referenced;
	ObjectAddresses *addrs;

	relation = table_open(CastRelationId, RowExclusiveLock);

	/*
	 * Check for duplicate.  This is just to give a friendly error message,
	 * the unique index would catch it anyway (so no need to sweat about race
	 * conditions).
	 */
	tuple = SearchSysCache2(CASTSOURCETARGET,
							ObjectIdGetDatum(sourcetypeid),
							ObjectIdGetDatum(targettypeid));
	if (HeapTupleIsValid(tuple))
		ereport(ERROR,
				(errcode(ERRCODE_DUPLICATE_OBJECT),
				 errmsg("cast from type %s to type %s already exists",
						format_type_be(sourcetypeid),
						format_type_be(targettypeid))));

	/* ready to go */
	castid = GetNewOidWithIndex(relation, CastOidIndexId, Anum_pg_cast_oid);
	values[Anum_pg_cast_oid - 1] = ObjectIdGetDatum(castid);
	values[Anum_pg_cast_castsource - 1] = ObjectIdGetDatum(sourcetypeid);
	values[Anum_pg_cast_casttarget - 1] = ObjectIdGetDatum(targettypeid);
	values[Anum_pg_cast_castfunc - 1] = ObjectIdGetDatum(funcid);
	values[Anum_pg_cast_castcontext - 1] = CharGetDatum(castcontext);
	values[Anum_pg_cast_castmethod - 1] = CharGetDatum(castmethod);

	tuple = heap_form_tuple(RelationGetDescr(relation), values, nulls);

	CatalogTupleInsert(relation, tuple);

	addrs = new_object_addresses();

	/* make dependency entries */
	ObjectAddressSet(myself, CastRelationId, castid);

	/* dependency on source type */
	ObjectAddressSet(referenced, TypeRelationId, sourcetypeid);
	add_exact_object_address(&referenced, addrs);

	/* dependency on target type */
	ObjectAddressSet(referenced, TypeRelationId, targettypeid);
	add_exact_object_address(&referenced, addrs);

	/* dependency on function */
	if (OidIsValid(funcid))
	{
		ObjectAddressSet(referenced, ProcedureRelationId, funcid);
		add_exact_object_address(&referenced, addrs);
	}

	/* dependencies on casts required for function */
	if (OidIsValid(incastid))
	{
		ObjectAddressSet(referenced, CastRelationId, incastid);
		add_exact_object_address(&referenced, addrs);
	}
	if (OidIsValid(outcastid))
	{
		ObjectAddressSet(referenced, CastRelationId, outcastid);
		add_exact_object_address(&referenced, addrs);
	}

	record_object_address_dependencies(&myself, addrs, behavior);
	free_object_addresses(addrs);

	/* dependency on extension */
	recordDependencyOnCurrentExtension(&myself, false);

	/* Post creation hook for new cast */
	InvokeObjectPostCreateHook(CastRelationId, castid, 0);

	heap_freetuple(tuple);

	table_close(relation, RowExclusiveLock);

	return myself;
}