Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.92) (envelope-from ) id 1jBPVY-0005ly-Ac for pgsql-hackers@arkaria.postgresql.org; Mon, 09 Mar 2020 21:00:16 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.89) (envelope-from ) id 1jBPVW-0006UM-8i for pgsql-hackers@arkaria.postgresql.org; Mon, 09 Mar 2020 21:00:14 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1jBPVV-0006U5-RC for pgsql-hackers@lists.postgresql.org; Mon, 09 Mar 2020 21:00:14 +0000 Received: from mail-qk1-x735.google.com ([2607:f8b0:4864:20::735]) by magus.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.92) (envelope-from ) id 1jBPVS-00009G-2i for pgsql-hackers@lists.postgresql.org; Mon, 09 Mar 2020 21:00:13 +0000 Received: by mail-qk1-x735.google.com with SMTP id h14so4763895qke.5 for ; Mon, 09 Mar 2020 14:00:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=2ndquadrant-com.20150623.gappssmtp.com; s=20150623; h=date:from:to:subject:message-id:mime-version:content-disposition :content-transfer-encoding:user-agent; bh=id1J+wX7qnUmtCFPDx6nyRzYEXf52oyjlHsEmOOzJo4=; b=Grs/l+SbA2xkEpfB7QeoI2a7O8e1Q1ppsNIVJxoFjnYX4DQBfcsxzCmFNw6IrK8qnP mOO+9p9K7TOABTqNhB3rDHNSORGl+cGlXwI4sfGLzfOzX5yJEL+rVdgUnpplIsFyl6Af 0KYmtwlo/ZAwGrPEKhhKAYFs6yIYi/eYo/oNb+r2KQIvg1Bffup2htY46qPz/6cRIXVk ursCvQ83S1fXJuqsQ+D3tV2TKx8dcItwZVWcp3MLA6GR0vzzG6rw7npm3F18g5oNceke FtyDU2WoGJ3SEGZgHGAoYPgR90b8ykE4JU3h/m+tvPrLPE4zfcg2q5MhVY5HSsuBKQPE 7ePA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:subject:message-id:mime-version :content-disposition:content-transfer-encoding:user-agent; bh=id1J+wX7qnUmtCFPDx6nyRzYEXf52oyjlHsEmOOzJo4=; b=nouy32kCEhxCJj6WLnC7e0Pr70xFQM2uuWA9H6EQ+VDdnvShEIVqc1jru6ddUY94aX dZ/CoU6rk8+y954iT7zkw6r36RUXB9lpn7dQ79Mj7uxcGUE9KSuommW/DAJ1kASE3UfC p2vVEIgV+dA5z1t+8/4rHqH9MZ8exUG+nLJIC96c43zrWbO2Zhjawc5caaSllyQ9se2R P2KqVEXth8B8jsSV+ckLWnbJf1A64ukEAsZE0DV+53uTDVWRicOP/cG8hi19ULvAuLq1 1ckvcPt9yQ0atdyXGXKYF+6pQvWxfO8DJJ3t18oYgp9Jp5PnCM2oR5eozsN2NygmQN49 I1zA== X-Gm-Message-State: ANhLgQ2hgL8nd9ec+QxryU8270+iBw6qMgp0AwEH0JKd09Ssl3nEuVsf Ld9Xy63hO10ubsPkSQne+VjET5OIMGpYmjt2cE068GTqXakwdnYm0z5LvKyVbVj8ubBaiE+3/kL vK7aCgtVpn0dL7x3hLnkH5y5X26KYkb8V1mzO+tstU0dsv0VA5OJwmXWce66CE9f9Gr366IqsFb HisZe4LvifJuyYW42X X-Google-Smtp-Source: ADFU+vt4FYGG4n4zikJuwnDqrH+kjVGB8yA4lMzhwXy6X4sNXs6hDot58PpXHTe4kKbdi9Awi/svnQ== X-Received: by 2002:a37:67c7:: with SMTP id b190mr7801151qkc.469.1583787607024; Mon, 09 Mar 2020 14:00:07 -0700 (PDT) Received: from nimloth.alvh.no-ip.org ([190.121.31.1]) by smtp.gmail.com with ESMTPSA id b5sm22601042qkh.58.2020.03.09.14.00.06 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 09 Mar 2020 14:00:06 -0700 (PDT) Received: by nimloth.alvh.no-ip.org (Postfix, from userid 1000) id 8B1ED3008D9; Mon, 9 Mar 2020 18:00:03 -0300 (-03) Date: Mon, 9 Mar 2020 18:00:03 -0300 From: Alvaro Herrera To: Pg Hackers Subject: time for catalog/pg_cast.c? Message-ID: <20200309210003.GA19992@alvherre.pgsql> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="XsQoSWH+UP9D9v3l" Content-Disposition: inline Content-Transfer-Encoding: 8bit User-Agent: Mutt/1.10.1 (2018-07-13) List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Precedence: bulk --XsQoSWH+UP9D9v3l Content-Type: text/plain; charset=iso-8859-1 Content-Disposition: inline Content-Transfer-Encoding: 8bit I extracted from the latest multirange patch a bit that creates a new routine CastCreate() in src/backend/catalog/pg_cast.c. It contains the catalog-accessing bits to create a new cast. It seems harmless, so I thought I'd apply it to get rid of a couple of hunks in the large patch. (I also threw in a move of get_cast_oid from functioncmds.c to lsyscache.c, which seems its natural place; at first I thought to put it in catalog/pg_cast.c but really it's not a great place IMO. This function was invented out of whole cloth in commit fd1843ff8979. I also contemplated the move of CreateCast and DropCastById from functioncmds.c to some new place, but creating a new commands/castcmds.c seemed a bit excessive, so I left them in their current locations.) -- Álvaro Herrera 39°49'30"S 73°17'W "The problem with the future is that it keeps turning into the present" (Hobbes) --XsQoSWH+UP9D9v3l Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="pg_cast.patch" commit 928aa3fa75a2f244dfb3ac08c4b4d166e426f9cf Author: Alvaro Herrera AuthorDate: Mon Mar 9 17:19:50 2020 -0300 CommitDate: Mon Mar 9 17:59:30 2020 -0300 add pg_cast.c for CastCreate() 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..19f410337d --- /dev/null +++ b/src/backend/catalog/pg_cast.c @@ -0,0 +1,116 @@ +/*------------------------------------------------------------------------- + * + * 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 + * ---------------------------------------------------------------- + */ +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 3da90cb72a..1955b846c2 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 5cd6975a22..cdb752243f 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 f132d39458..52d4c77260 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); --XsQoSWH+UP9D9v3l--