Allow ALTER TYPE to update an existing type's typsubscript value.
authorTom Lane <[email protected]>
Fri, 11 Dec 2020 23:07:02 +0000 (18:07 -0500)
committerTom Lane <[email protected]>
Fri, 11 Dec 2020 23:58:21 +0000 (18:58 -0500)
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
src/backend/commands/typecmds.c
src/test/regress/expected/create_type.out
src/test/regress/sql/create_type.sql

index 64bf266373d45d86153b3a09e9ea3bb36b5c072f..21887e88a0f2e1d0e674a4514bb538582d0b4a82 100644 (file)
@@ -194,6 +194,14 @@ ALTER TYPE <replaceable class="parameter">name</replaceable> SET ( <replaceable
          requires superuser privilege.
         </para>
        </listitem>
+       <listitem>
+        <para>
+         <literal>SUBSCRIPT</literal> can be set to the name of a type-specific
+         subscripting handler function, or <literal>NONE</literal> to remove
+         the type's subscripting handler function.  Using this option
+         requires superuser privilege.
+        </para>
+       </listitem>
        <listitem>
         <para>
          <literal>STORAGE</literal><indexterm>
index 29fe52d2cefe01cccededb6998cb1c089b0a860c..7c0b2c3bf0223c790274dba417e85632d7202a81 100644 (file)
@@ -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 ||
index f85afcb31edf1cf0b2fd880718580859d1276eed..14394cc95cdd091d5777e82d7ff2cd59a3531c6e 100644 (file)
@@ -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
index 584ece06701d32682f585dc49b714ab307057dfa..a32a9e67957e529384e09c7240cbd88b456414a7 100644 (file)
@@ -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