Commit 3d2376d5 authored by Tom Lane's avatar Tom Lane

Fix oversight in ALTER TYPE: typmodin/typmodout must propagate to arrays.

If a base type supports typmods, its array type does too, with the
same interpretation.  Hence changes in pg_type.typmodin/typmodout
must be propagated to the array type.

While here, improve AlterTypeRecurse to not recurse to domains if
there is nothing we'd need to change.

Oversight in fe30e7eb.  Back-patch to v13 where that came in.
parent 78e73e87
......@@ -127,7 +127,8 @@ static char *domainAddConstraint(Oid domainOid, Oid domainNamespace,
const char *domainName, ObjectAddress *constrAddr);
static Node *replace_domain_constraint_value(ParseState *pstate,
ColumnRef *cref);
static void AlterTypeRecurse(Oid typeOid, HeapTuple tup, Relation catalog,
static void AlterTypeRecurse(Oid typeOid, bool isImplicitArray,
HeapTuple tup, Relation catalog,
AlterTypeRecurseParams *atparams);
......@@ -3853,8 +3854,8 @@ AlterType(AlterTypeStmt *stmt)
errmsg("%s is not a base type",
format_type_be(typeOid))));
/* OK, recursively update this type and any domains over it */
AlterTypeRecurse(typeOid, tup, catalog, &atparams);
/* OK, recursively update this type and any arrays/domains over it */
AlterTypeRecurse(typeOid, false, tup, catalog, &atparams);
/* Clean up */
ReleaseSysCache(tup);
......@@ -3870,13 +3871,15 @@ AlterType(AlterTypeStmt *stmt)
* AlterTypeRecurse: one recursion step for AlterType()
*
* Apply the changes specified by "atparams" to the type identified by
* "typeOid", whose existing pg_type tuple is "tup". Then search for any
* domains over this type, and recursively apply (most of) the same changes
* to those domains.
* "typeOid", whose existing pg_type tuple is "tup". If necessary,
* recursively update its array type as well. Then search for any domains
* over this type, and recursively apply (most of) the same changes to those
* domains.
*
* We need this because the system generally assumes that a domain inherits
* many properties from its base type. See DefineDomain() above for details
* of what is inherited.
* of what is inherited. Arrays inherit a smaller number of properties,
* but not none.
*
* There's a race condition here, in that some other transaction could
* concurrently add another domain atop this base type; we'd miss updating
......@@ -3888,7 +3891,8 @@ AlterType(AlterTypeStmt *stmt)
* committed.
*/
static void
AlterTypeRecurse(Oid typeOid, HeapTuple tup, Relation catalog,
AlterTypeRecurse(Oid typeOid, bool isImplicitArray,
HeapTuple tup, Relation catalog,
AlterTypeRecurseParams *atparams)
{
Datum values[Natts_pg_type];
......@@ -3949,12 +3953,43 @@ AlterTypeRecurse(Oid typeOid, HeapTuple tup, Relation catalog,
NULL, /* don't have defaultExpr handy */
NULL, /* don't have typacl handy */
0, /* we rejected composite types above */
false, /* and we rejected implicit arrays above */
false, /* so it can't be a dependent type */
isImplicitArray, /* it might be an array */
isImplicitArray, /* dependent iff it's array */
true);
InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
/*
* Arrays inherit their base type's typmodin and typmodout, but none of
* the other properties we're concerned with here. Recurse to the array
* type if needed.
*/
if (!isImplicitArray &&
(atparams->updateTypmodin || atparams->updateTypmodout))
{
Oid arrtypoid = ((Form_pg_type) GETSTRUCT(newtup))->typarray;
if (OidIsValid(arrtypoid))
{
HeapTuple arrtup;
AlterTypeRecurseParams arrparams;
arrtup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(arrtypoid));
if (!HeapTupleIsValid(arrtup))
elog(ERROR, "cache lookup failed for type %u", arrtypoid);
memset(&arrparams, 0, sizeof(arrparams));
arrparams.updateTypmodin = atparams->updateTypmodin;
arrparams.updateTypmodout = atparams->updateTypmodout;
arrparams.typmodinOid = atparams->typmodinOid;
arrparams.typmodoutOid = atparams->typmodoutOid;
AlterTypeRecurse(arrtypoid, true, arrtup, catalog, &arrparams);
ReleaseSysCache(arrtup);
}
}
/*
* Now we need to recurse to domains. However, some properties are not
* inherited by domains, so clear the update flags for those.
......@@ -3963,6 +3998,12 @@ AlterTypeRecurse(Oid typeOid, HeapTuple tup, Relation catalog,
atparams->updateTypmodin = false; /* domains don't have typmods */
atparams->updateTypmodout = false;
/* Skip the scan if nothing remains to be done */
if (!(atparams->updateStorage ||
atparams->updateSend ||
atparams->updateAnalyze))
return;
/* Search pg_type for possible domains over this type */
ScanKeyInit(&key[0],
Anum_pg_type_typbasetype,
......@@ -3983,7 +4024,7 @@ AlterTypeRecurse(Oid typeOid, HeapTuple tup, Relation catalog,
if (domainForm->typtype != TYPTYPE_DOMAIN)
continue;
AlterTypeRecurse(domainForm->oid, domainTup, catalog, atparams);
AlterTypeRecurse(domainForm->oid, false, domainTup, catalog, atparams);
}
systable_endscan(scan);
......
......@@ -270,6 +270,14 @@ FROM pg_type WHERE typname = 'myvarchar';
myvarcharin | myvarcharout | myvarcharrecv | myvarcharsend | varchartypmodin | varchartypmodout | array_typanalyze | x
(1 row)
SELECT typinput, typoutput, typreceive, typsend, typmodin, typmodout,
typanalyze, 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
(1 row)
SELECT typinput, typoutput, typreceive, typsend, typmodin, typmodout,
typanalyze, typstorage
FROM pg_type WHERE typname = 'myvarchardom';
......@@ -278,6 +286,14 @@ FROM pg_type WHERE typname = 'myvarchardom';
domain_in | myvarcharout | domain_recv | myvarcharsend | - | - | array_typanalyze | x
(1 row)
SELECT typinput, typoutput, typreceive, typsend, typmodin, typmodout,
typanalyze, 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
(1 row)
-- ensure dependencies are straight
DROP FUNCTION myvarcharsend(myvarchar); -- fail
ERROR: cannot drop function myvarcharsend(myvarchar) because other objects depend on it
......
......@@ -214,10 +214,18 @@ SELECT typinput, typoutput, typreceive, typsend, typmodin, typmodout,
typanalyze, typstorage
FROM pg_type WHERE typname = 'myvarchar';
SELECT typinput, typoutput, typreceive, typsend, typmodin, typmodout,
typanalyze, typstorage
FROM pg_type WHERE typname = '_myvarchar';
SELECT typinput, typoutput, typreceive, typsend, typmodin, typmodout,
typanalyze, typstorage
FROM pg_type WHERE typname = 'myvarchardom';
SELECT typinput, typoutput, typreceive, typsend, typmodin, typmodout,
typanalyze, typstorage
FROM pg_type WHERE typname = '_myvarchardom';
-- ensure dependencies are straight
DROP FUNCTION myvarcharsend(myvarchar); -- fail
DROP TYPE myvarchar; -- fail
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment