From 8c15a297452e970d68529ee2ce6bd94d84598409 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Fri, 11 Dec 2020 18:07:02 -0500 Subject: [PATCH] Allow ALTER TYPE to update an existing type's typsubscript value. This is essential if we'd like to allow existing extension data types to support subscripting in future, since dropping and recreating the type isn't a practical thing for an extension upgrade script, and direct manipulation of pg_type isn't a great answer either. There was some discussion about also allowing alteration of typelem, but it's less clear whether that's a good idea or not, so for now I forebore. Discussion: https://postgr.es/m/3724341.1607551174@sss.pgh.pa.us --- doc/src/sgml/ref/alter_type.sgml | 8 +++++ src/backend/commands/typecmds.c | 20 +++++++++++++ src/test/regress/expected/create_type.out | 36 ++++++++++++----------- src/test/regress/sql/create_type.sql | 12 ++++---- 4 files changed, 54 insertions(+), 22 deletions(-) diff --git a/doc/src/sgml/ref/alter_type.sgml b/doc/src/sgml/ref/alter_type.sgml index 64bf266373d..21887e88a0f 100644 --- a/doc/src/sgml/ref/alter_type.sgml +++ b/doc/src/sgml/ref/alter_type.sgml @@ -194,6 +194,14 @@ ALTER TYPE name SET ( + + + SUBSCRIPT can be set to the name of a type-specific + subscripting handler function, or NONE to remove + the type's subscripting handler function. Using this option + requires superuser privilege. + + STORAGE diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c index 29fe52d2cef..7c0b2c3bf02 100644 --- a/src/backend/commands/typecmds.c +++ b/src/backend/commands/typecmds.c @@ -94,6 +94,7 @@ typedef struct bool updateTypmodin; bool updateTypmodout; bool updateAnalyze; + bool updateSubscript; /* New values for relevant attributes */ char storage; Oid receiveOid; @@ -101,6 +102,7 @@ typedef struct Oid typmodinOid; Oid typmodoutOid; Oid analyzeOid; + Oid subscriptOid; } AlterTypeRecurseParams; /* Potentially set by pg_upgrade_support functions */ @@ -3885,6 +3887,18 @@ AlterType(AlterTypeStmt *stmt) /* Replacing an analyze function requires superuser. */ requireSuper = true; } + else if (strcmp(defel->defname, "subscript") == 0) + { + if (defel->arg != NULL) + atparams.subscriptOid = + findTypeSubscriptingFunction(defGetQualifiedName(defel), + typeOid); + else + atparams.subscriptOid = InvalidOid; /* NONE, remove function */ + atparams.updateSubscript = true; + /* Replacing a subscript function requires superuser. */ + requireSuper = true; + } /* * The rest of the options that CREATE accepts cannot be changed. @@ -4042,6 +4056,11 @@ AlterTypeRecurse(Oid typeOid, bool isImplicitArray, replaces[Anum_pg_type_typanalyze - 1] = true; values[Anum_pg_type_typanalyze - 1] = ObjectIdGetDatum(atparams->analyzeOid); } + if (atparams->updateSubscript) + { + replaces[Anum_pg_type_typsubscript - 1] = true; + values[Anum_pg_type_typsubscript - 1] = ObjectIdGetDatum(atparams->subscriptOid); + } newtup = heap_modify_tuple(tup, RelationGetDescr(catalog), values, nulls, replaces); @@ -4098,6 +4117,7 @@ AlterTypeRecurse(Oid typeOid, bool isImplicitArray, atparams->updateReceive = false; /* domains use F_DOMAIN_RECV */ atparams->updateTypmodin = false; /* domains don't have typmods */ atparams->updateTypmodout = false; + atparams->updateSubscript = false; /* domains don't have subscriptors */ /* Skip the scan if nothing remains to be done */ if (!(atparams->updateStorage || diff --git a/src/test/regress/expected/create_type.out b/src/test/regress/expected/create_type.out index f85afcb31ed..14394cc95cd 100644 --- a/src/test/regress/expected/create_type.out +++ b/src/test/regress/expected/create_type.out @@ -260,38 +260,40 @@ ALTER TYPE myvarchar SET ( receive = myvarcharrecv, typmod_in = varchartypmodin, typmod_out = varchartypmodout, - analyze = array_typanalyze -- bogus, but it doesn't matter + -- these are bogus, but it's safe as long as we don't use the type: + analyze = ts_typanalyze, + subscript = raw_array_subscript_handler ); SELECT typinput, typoutput, typreceive, typsend, typmodin, typmodout, - typanalyze, typstorage + typanalyze, typsubscript, typstorage FROM pg_type WHERE typname = 'myvarchar'; - typinput | typoutput | typreceive | typsend | typmodin | typmodout | typanalyze | typstorage --------------+--------------+---------------+---------------+-----------------+------------------+------------------+------------ - myvarcharin | myvarcharout | myvarcharrecv | myvarcharsend | varchartypmodin | varchartypmodout | array_typanalyze | x + typinput | typoutput | typreceive | typsend | typmodin | typmodout | typanalyze | typsubscript | typstorage +-------------+--------------+---------------+---------------+-----------------+------------------+---------------+-----------------------------+------------ + myvarcharin | myvarcharout | myvarcharrecv | myvarcharsend | varchartypmodin | varchartypmodout | ts_typanalyze | raw_array_subscript_handler | x (1 row) SELECT typinput, typoutput, typreceive, typsend, typmodin, typmodout, - typanalyze, typstorage + typanalyze, typsubscript, typstorage FROM pg_type WHERE typname = '_myvarchar'; - typinput | typoutput | typreceive | typsend | typmodin | typmodout | typanalyze | typstorage -----------+-----------+------------+------------+-----------------+------------------+------------------+------------ - array_in | array_out | array_recv | array_send | varchartypmodin | varchartypmodout | array_typanalyze | x + typinput | typoutput | typreceive | typsend | typmodin | typmodout | typanalyze | typsubscript | typstorage +----------+-----------+------------+------------+-----------------+------------------+------------------+-------------------------+------------ + array_in | array_out | array_recv | array_send | varchartypmodin | varchartypmodout | array_typanalyze | array_subscript_handler | x (1 row) SELECT typinput, typoutput, typreceive, typsend, typmodin, typmodout, - typanalyze, typstorage + typanalyze, typsubscript, typstorage FROM pg_type WHERE typname = 'myvarchardom'; - typinput | typoutput | typreceive | typsend | typmodin | typmodout | typanalyze | typstorage ------------+--------------+-------------+---------------+----------+-----------+------------------+------------ - domain_in | myvarcharout | domain_recv | myvarcharsend | - | - | array_typanalyze | x + typinput | typoutput | typreceive | typsend | typmodin | typmodout | typanalyze | typsubscript | typstorage +-----------+--------------+-------------+---------------+----------+-----------+---------------+--------------+------------ + domain_in | myvarcharout | domain_recv | myvarcharsend | - | - | ts_typanalyze | - | x (1 row) SELECT typinput, typoutput, typreceive, typsend, typmodin, typmodout, - typanalyze, typstorage + typanalyze, typsubscript, typstorage FROM pg_type WHERE typname = '_myvarchardom'; - typinput | typoutput | typreceive | typsend | typmodin | typmodout | typanalyze | typstorage -----------+-----------+------------+------------+----------+-----------+------------------+------------ - array_in | array_out | array_recv | array_send | - | - | array_typanalyze | x + typinput | typoutput | typreceive | typsend | typmodin | typmodout | typanalyze | typsubscript | typstorage +----------+-----------+------------+------------+----------+-----------+------------------+-------------------------+------------ + array_in | array_out | array_recv | array_send | - | - | array_typanalyze | array_subscript_handler | x (1 row) -- ensure dependencies are straight diff --git a/src/test/regress/sql/create_type.sql b/src/test/regress/sql/create_type.sql index 584ece06701..a32a9e67957 100644 --- a/src/test/regress/sql/create_type.sql +++ b/src/test/regress/sql/create_type.sql @@ -207,23 +207,25 @@ ALTER TYPE myvarchar SET ( receive = myvarcharrecv, typmod_in = varchartypmodin, typmod_out = varchartypmodout, - analyze = array_typanalyze -- bogus, but it doesn't matter + -- these are bogus, but it's safe as long as we don't use the type: + analyze = ts_typanalyze, + subscript = raw_array_subscript_handler ); SELECT typinput, typoutput, typreceive, typsend, typmodin, typmodout, - typanalyze, typstorage + typanalyze, typsubscript, typstorage FROM pg_type WHERE typname = 'myvarchar'; SELECT typinput, typoutput, typreceive, typsend, typmodin, typmodout, - typanalyze, typstorage + typanalyze, typsubscript, typstorage FROM pg_type WHERE typname = '_myvarchar'; SELECT typinput, typoutput, typreceive, typsend, typmodin, typmodout, - typanalyze, typstorage + typanalyze, typsubscript, typstorage FROM pg_type WHERE typname = 'myvarchardom'; SELECT typinput, typoutput, typreceive, typsend, typmodin, typmodout, - typanalyze, typstorage + typanalyze, typsubscript, typstorage FROM pg_type WHERE typname = '_myvarchardom'; -- ensure dependencies are straight -- 2.30.2