diff --git a/src/backend/catalog/Makefile b/src/backend/catalog/Makefile index f8f0b4841c..9499bb33e5 100644 --- a/src/backend/catalog/Makefile +++ b/src/backend/catalog/Makefile @@ -25,6 +25,7 @@ OBJS = \ objectaddress.o \ partition.o \ pg_aggregate.o \ + pg_cast.o \ pg_collation.o \ pg_constraint.o \ pg_conversion.o \ diff --git a/src/backend/catalog/pg_cast.c b/src/backend/catalog/pg_cast.c new file mode 100644 index 0000000000..3854455637 --- /dev/null +++ b/src/backend/catalog/pg_cast.c @@ -0,0 +1,123 @@ +/*------------------------------------------------------------------------- + * + * pg_cast.c + * routines to support manipulation of the pg_cast relation + * + * Portions Copyright (c) 1996-2019, 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). + * + * 'behavior' indicates the types of the dependencies that the new + * cast will have on its input and output types and the cast function. + * ---------------------------------------------------------------- + */ +ObjectAddress +CastCreate(Oid sourcetypeid, Oid targettypeid, Oid funcid, char castcontext, + char castmethod, DependencyType behavior) +{ + Relation relation; + HeapTuple tuple; + Oid castid; + Datum values[Natts_pg_cast]; + bool nulls[Natts_pg_cast]; + ObjectAddress myself, + referenced; + + 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); + + MemSet(nulls, false, sizeof(nulls)); + + tuple = heap_form_tuple(RelationGetDescr(relation), values, nulls); + + CatalogTupleInsert(relation, tuple); + + /* make dependency entries */ + myself.classId = CastRelationId; + myself.objectId = castid; + myself.objectSubId = 0; + + /* dependency on source type */ + referenced.classId = TypeRelationId; + referenced.objectId = sourcetypeid; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, behavior); + + /* dependency on target type */ + referenced.classId = TypeRelationId; + referenced.objectId = targettypeid; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, behavior); + + /* dependency on function */ + if (OidIsValid(funcid)) + { + referenced.classId = ProcedureRelationId; + referenced.objectId = funcid; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, behavior); + } + + /* 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; +} diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c index 43a23c69af..5eac55aaca 100644 --- a/src/backend/commands/functioncmds.c +++ b/src/backend/commands/functioncmds.c @@ -1411,17 +1411,12 @@ CreateCast(CreateCastStmt *stmt) char sourcetyptype; char targettyptype; Oid funcid; - Oid castid; int nargs; char castcontext; char castmethod; - Relation relation; HeapTuple tuple; - Datum values[Natts_pg_cast]; - bool nulls[Natts_pg_cast]; - ObjectAddress myself, - referenced; AclResult aclresult; + ObjectAddress myself; sourcetypeid = typenameTypeId(NULL, stmt->sourcetype); targettypeid = typenameTypeId(NULL, stmt->targettype); @@ -1645,100 +1640,11 @@ CreateCast(CreateCastStmt *stmt) break; } - 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); - - MemSet(nulls, false, sizeof(nulls)); - - tuple = heap_form_tuple(RelationGetDescr(relation), values, nulls); - - CatalogTupleInsert(relation, tuple); - - /* make dependency entries */ - myself.classId = CastRelationId; - myself.objectId = castid; - myself.objectSubId = 0; - - /* dependency on source type */ - referenced.classId = TypeRelationId; - referenced.objectId = sourcetypeid; - referenced.objectSubId = 0; - recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); - - /* dependency on target type */ - referenced.classId = TypeRelationId; - referenced.objectId = targettypeid; - referenced.objectSubId = 0; - recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); - - /* dependency on function */ - if (OidIsValid(funcid)) - { - referenced.classId = ProcedureRelationId; - referenced.objectId = funcid; - referenced.objectSubId = 0; - recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); - } - - /* dependency on extension */ - recordDependencyOnCurrentExtension(&myself, false); - - /* Post creation hook for new cast */ - InvokeObjectPostCreateHook(CastRelationId, castid, 0); - - heap_freetuple(tuple); - - table_close(relation, RowExclusiveLock); - + myself = CastCreate(sourcetypeid, targettypeid, funcid, castcontext, + castmethod, DEPENDENCY_NORMAL); return myself; } -/* - * get_cast_oid - given two type OIDs, look up a cast OID - * - * If missing_ok is false, throw an error if the cast is not found. If - * true, just return InvalidOid. - */ -Oid -get_cast_oid(Oid sourcetypeid, Oid targettypeid, bool missing_ok) -{ - Oid oid; - - oid = GetSysCacheOid2(CASTSOURCETARGET, Anum_pg_cast_oid, - ObjectIdGetDatum(sourcetypeid), - ObjectIdGetDatum(targettypeid)); - if (!OidIsValid(oid) && !missing_ok) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("cast from type %s to type %s does not exist", - format_type_be(sourcetypeid), - format_type_be(targettypeid)))); - return oid; -} - void DropCastById(Oid castOid) { diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c index b088ca848d..8891b1d564 100644 --- a/src/backend/commands/typecmds.c +++ b/src/backend/commands/typecmds.c @@ -42,6 +42,7 @@ #include "catalog/objectaccess.h" #include "catalog/pg_am.h" #include "catalog/pg_authid.h" +#include "catalog/pg_cast.h" #include "catalog/pg_collation.h" #include "catalog/pg_constraint.h" #include "catalog/pg_depend.h" diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c index 400e7689fe..6b24369de8 100644 --- a/src/backend/utils/cache/lsyscache.c +++ b/src/backend/utils/cache/lsyscache.c @@ -23,6 +23,7 @@ #include "catalog/pg_am.h" #include "catalog/pg_amop.h" #include "catalog/pg_amproc.h" +#include "catalog/pg_cast.h" #include "catalog/pg_collation.h" #include "catalog/pg_constraint.h" #include "catalog/pg_language.h" @@ -908,6 +909,31 @@ get_atttypetypmodcoll(Oid relid, AttrNumber attnum, ReleaseSysCache(tp); } +/* ---------- PG_CAST CACHE ---------- */ + +/* + * get_cast_oid - given two type OIDs, look up a cast OID + * + * If missing_ok is false, throw an error if the cast is not found. If + * true, just return InvalidOid. + */ +Oid +get_cast_oid(Oid sourcetypeid, Oid targettypeid, bool missing_ok) +{ + Oid oid; + + oid = GetSysCacheOid2(CASTSOURCETARGET, Anum_pg_cast_oid, + ObjectIdGetDatum(sourcetypeid), + ObjectIdGetDatum(targettypeid)); + if (!OidIsValid(oid) && !missing_ok) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("cast from type %s to type %s does not exist", + format_type_be(sourcetypeid), + format_type_be(targettypeid)))); + return oid; +} + /* ---------- COLLATION CACHE ---------- */ /* diff --git a/src/include/catalog/pg_cast.h b/src/include/catalog/pg_cast.h index 1b81b52df6..2620ff40f0 100644 --- a/src/include/catalog/pg_cast.h +++ b/src/include/catalog/pg_cast.h @@ -20,6 +20,7 @@ #ifndef PG_CAST_H #define PG_CAST_H +#include "catalog/dependency.h" #include "catalog/genbki.h" #include "catalog/pg_cast_d.h" @@ -87,4 +88,12 @@ typedef enum CoercionMethod #endif /* EXPOSE_TO_CLIENT_CODE */ + +extern ObjectAddress CastCreate(Oid sourcetypeid, + Oid targettypeid, + Oid funcid, + char castcontext, + char castmethod, + DependencyType behavior); + #endif /* PG_CAST_H */ diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h index 08ca6ac31e..c77c9a6ed5 100644 --- a/src/include/commands/defrem.h +++ b/src/include/commands/defrem.h @@ -64,7 +64,6 @@ extern void IsThereFunctionInNamespace(const char *proname, int pronargs, extern void ExecuteDoStmt(DoStmt *stmt, bool atomic); extern void ExecuteCallStmt(CallStmt *stmt, ParamListInfo params, bool atomic, DestReceiver *dest); extern TupleDesc CallStmtResultDesc(CallStmt *stmt); -extern Oid get_cast_oid(Oid sourcetypeid, Oid targettypeid, bool missing_ok); extern Oid get_transform_oid(Oid type_id, Oid lang_id, bool missing_ok); extern void interpret_function_parameter_list(ParseState *pstate, List *parameters, diff --git a/src/include/utils/lsyscache.h b/src/include/utils/lsyscache.h index 131d10eab0..6e93590bef 100644 --- a/src/include/utils/lsyscache.h +++ b/src/include/utils/lsyscache.h @@ -90,6 +90,7 @@ extern char get_attgenerated(Oid relid, AttrNumber attnum); extern Oid get_atttype(Oid relid, AttrNumber attnum); extern void get_atttypetypmodcoll(Oid relid, AttrNumber attnum, Oid *typid, int32 *typmod, Oid *collid); +extern Oid get_cast_oid(Oid sourcetypeid, Oid targettypeid, bool missing_ok); extern char *get_collation_name(Oid colloid); extern bool get_collation_isdeterministic(Oid colloid); extern char *get_constraint_name(Oid conoid);