diff options
author | Tom Lane | 2020-03-05 20:48:56 +0000 |
---|---|---|
committer | Tom Lane | 2020-03-05 20:48:56 +0000 |
commit | bb03010b9f0766e10399174fe850b2506907c4e4 (patch) | |
tree | b74a4c09b4b9c93c890f6f504f12446b09d6ed89 /src/backend | |
parent | 84eca14bc4bdf71911cceb3a6286bc47db3a5a06 (diff) |
Remove the "opaque" pseudo-type and associated compatibility hacks.
A long time ago, it was necessary to declare datatype I/O functions,
triggers, and language handler support functions in a very type-unsafe
way involving a single pseudo-type "opaque". We got rid of those
conventions in 7.3, but there was still support in various places to
automatically convert such functions to the modern declaration style,
to be able to transparently re-load dumps from pre-7.3 servers.
It seems unnecessary to continue to support that anymore, so take out
the hacks; whereupon the "opaque" pseudo-type itself is no longer
needed and can be dropped.
This is part of a group of patches removing various server-side kluges
for transparently upgrading pre-8.0 dump files. Since we've had few
complaints about dropping pg_dump's support for dumping from pre-8.0
servers (commit 64f3524e2), it seems okay to now remove these kluges.
Discussion: https://postgr.es/m/4110.1583255415@sss.pgh.pa.us
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/commands/functioncmds.c | 87 | ||||
-rw-r--r-- | src/backend/commands/proclang.c | 25 | ||||
-rw-r--r-- | src/backend/commands/trigger.c | 23 | ||||
-rw-r--r-- | src/backend/commands/typecmds.c | 282 | ||||
-rw-r--r-- | src/backend/utils/adt/pseudotypes.c | 1 |
5 files changed, 99 insertions, 319 deletions
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c index 6d824a5ebfb..43a23c69af3 100644 --- a/src/backend/commands/functioncmds.c +++ b/src/backend/commands/functioncmds.c @@ -1399,93 +1399,6 @@ AlterFunction(ParseState *pstate, AlterFunctionStmt *stmt) return address; } -/* - * SetFunctionReturnType - change declared return type of a function - * - * This is presently only used for adjusting legacy functions that return - * OPAQUE to return whatever we find their correct definition should be. - * The caller should emit a suitable warning explaining what we did. - */ -void -SetFunctionReturnType(Oid funcOid, Oid newRetType) -{ - Relation pg_proc_rel; - HeapTuple tup; - Form_pg_proc procForm; - ObjectAddress func_address; - ObjectAddress type_address; - - pg_proc_rel = table_open(ProcedureRelationId, RowExclusiveLock); - - tup = SearchSysCacheCopy1(PROCOID, ObjectIdGetDatum(funcOid)); - if (!HeapTupleIsValid(tup)) /* should not happen */ - elog(ERROR, "cache lookup failed for function %u", funcOid); - procForm = (Form_pg_proc) GETSTRUCT(tup); - - if (procForm->prorettype != OPAQUEOID) /* caller messed up */ - elog(ERROR, "function %u doesn't return OPAQUE", funcOid); - - /* okay to overwrite copied tuple */ - procForm->prorettype = newRetType; - - /* update the catalog and its indexes */ - CatalogTupleUpdate(pg_proc_rel, &tup->t_self, tup); - - table_close(pg_proc_rel, RowExclusiveLock); - - /* - * Also update the dependency to the new type. Opaque is a pinned type, so - * there is no old dependency record for it that we would need to remove. - */ - ObjectAddressSet(type_address, TypeRelationId, newRetType); - ObjectAddressSet(func_address, ProcedureRelationId, funcOid); - recordDependencyOn(&func_address, &type_address, DEPENDENCY_NORMAL); -} - - -/* - * SetFunctionArgType - change declared argument type of a function - * - * As above, but change an argument's type. - */ -void -SetFunctionArgType(Oid funcOid, int argIndex, Oid newArgType) -{ - Relation pg_proc_rel; - HeapTuple tup; - Form_pg_proc procForm; - ObjectAddress func_address; - ObjectAddress type_address; - - pg_proc_rel = table_open(ProcedureRelationId, RowExclusiveLock); - - tup = SearchSysCacheCopy1(PROCOID, ObjectIdGetDatum(funcOid)); - if (!HeapTupleIsValid(tup)) /* should not happen */ - elog(ERROR, "cache lookup failed for function %u", funcOid); - procForm = (Form_pg_proc) GETSTRUCT(tup); - - if (argIndex < 0 || argIndex >= procForm->pronargs || - procForm->proargtypes.values[argIndex] != OPAQUEOID) - elog(ERROR, "function %u doesn't take OPAQUE", funcOid); - - /* okay to overwrite copied tuple */ - procForm->proargtypes.values[argIndex] = newArgType; - - /* update the catalog and its indexes */ - CatalogTupleUpdate(pg_proc_rel, &tup->t_self, tup); - - table_close(pg_proc_rel, RowExclusiveLock); - - /* - * Also update the dependency to the new type. Opaque is a pinned type, so - * there is no old dependency record for it that we would need to remove. - */ - ObjectAddressSet(type_address, TypeRelationId, newArgType); - ObjectAddressSet(func_address, ProcedureRelationId, funcOid); - recordDependencyOn(&func_address, &type_address, DEPENDENCY_NORMAL); -} - - /* * CREATE CAST diff --git a/src/backend/commands/proclang.c b/src/backend/commands/proclang.c index 9d72edbfec5..21ceeb7e9a1 100644 --- a/src/backend/commands/proclang.c +++ b/src/backend/commands/proclang.c @@ -74,27 +74,10 @@ CreateProceduralLanguage(CreatePLangStmt *stmt) handlerOid = LookupFuncName(stmt->plhandler, 0, NULL, false); funcrettype = get_func_rettype(handlerOid); if (funcrettype != LANGUAGE_HANDLEROID) - { - /* - * We allow OPAQUE just so we can load old dump files. When we see a - * handler function declared OPAQUE, change it to LANGUAGE_HANDLER. - * (This is probably obsolete and removable?) - */ - if (funcrettype == OPAQUEOID) - { - ereport(WARNING, - (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("changing return type of function %s from %s to %s", - NameListToString(stmt->plhandler), - "opaque", "language_handler"))); - SetFunctionReturnType(handlerOid, LANGUAGE_HANDLEROID); - } - else - ereport(ERROR, - (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("function %s must return type %s", - NameListToString(stmt->plhandler), "language_handler"))); - } + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("function %s must return type %s", + NameListToString(stmt->plhandler), "language_handler"))); /* validate the inline function */ if (stmt->plinline) diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c index 35b4bb35106..b408efb11ea 100644 --- a/src/backend/commands/trigger.c +++ b/src/backend/commands/trigger.c @@ -694,25 +694,10 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString, } funcrettype = get_func_rettype(funcoid); if (funcrettype != TRIGGEROID) - { - /* - * We allow OPAQUE just so we can load old dump files. When we see a - * trigger function declared OPAQUE, change it to TRIGGER. - */ - if (funcrettype == OPAQUEOID) - { - ereport(WARNING, - (errmsg("changing return type of function %s from %s to %s", - NameListToString(stmt->funcname), - "opaque", "trigger"))); - SetFunctionReturnType(funcoid, TRIGGEROID); - } - else - ereport(ERROR, - (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), - errmsg("function %s must return type %s", - NameListToString(stmt->funcname), "trigger"))); - } + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("function %s must return type %s", + NameListToString(stmt->funcname), "trigger"))); /* * If it's a user-entered CREATE CONSTRAINT TRIGGER command, make a diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c index 99528bf1d58..d732a3af450 100644 --- a/src/backend/commands/typecmds.c +++ b/src/backend/commands/typecmds.c @@ -163,7 +163,6 @@ DefineType(ParseState *pstate, List *names, List *parameters) char *array_type; Oid array_oid; Oid typoid; - Oid resulttype; ListCell *pl; ObjectAddress address; @@ -196,8 +195,7 @@ DefineType(ParseState *pstate, List *names, List *parameters) #endif /* - * Look to see if type already exists (presumably as a shell; if not, - * TypeCreate will complain). + * Look to see if type already exists. */ typoid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid, CStringGetDatum(typeName), @@ -211,35 +209,37 @@ DefineType(ParseState *pstate, List *names, List *parameters) { if (moveArrayTypeName(typoid, typeName, typeNamespace)) typoid = InvalidOid; + else + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("type \"%s\" already exists", typeName))); } /* - * If it doesn't exist, create it as a shell, so that the OID is known for - * use in the I/O function definitions. + * If this command is a parameterless CREATE TYPE, then we're just here to + * make a shell type, so do that (or fail if there already is a shell). */ - if (!OidIsValid(typoid)) + if (parameters == NIL) { - address = TypeShellMake(typeName, typeNamespace, GetUserId()); - typoid = address.objectId; - /* Make new shell type visible for modification below */ - CommandCounterIncrement(); - - /* - * If the command was a parameterless CREATE TYPE, we're done --- - * creating the shell type was all we're supposed to do. - */ - if (parameters == NIL) - return address; - } - else - { - /* Complain if dummy CREATE TYPE and entry already exists */ - if (parameters == NIL) + if (OidIsValid(typoid)) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("type \"%s\" already exists", typeName))); + + address = TypeShellMake(typeName, typeNamespace, GetUserId()); + return address; } + /* + * Otherwise, we must already have a shell type, since there is no other + * way that the I/O functions could have been created. + */ + if (!OidIsValid(typoid)) + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("type \"%s\" does not exist", typeName), + errhint("Create the type as a shell type, then create its I/O functions, then do a full CREATE TYPE."))); + /* Extract the parameters from the parameter list */ foreach(pl, parameters) { @@ -445,63 +445,6 @@ DefineType(ParseState *pstate, List *names, List *parameters) sendOid = findTypeSendFunction(sendName, typoid); /* - * Verify that I/O procs return the expected thing. If we see OPAQUE, - * complain and change it to the correct type-safe choice. - */ - resulttype = get_func_rettype(inputOid); - if (resulttype != typoid) - { - if (resulttype == OPAQUEOID) - { - /* backwards-compatibility hack */ - ereport(WARNING, - (errmsg("changing return type of function %s from %s to %s", - NameListToString(inputName), "opaque", typeName))); - SetFunctionReturnType(inputOid, typoid); - } - else - ereport(ERROR, - (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), - errmsg("type input function %s must return type %s", - NameListToString(inputName), typeName))); - } - resulttype = get_func_rettype(outputOid); - if (resulttype != CSTRINGOID) - { - if (resulttype == OPAQUEOID) - { - /* backwards-compatibility hack */ - ereport(WARNING, - (errmsg("changing return type of function %s from %s to %s", - NameListToString(outputName), "opaque", "cstring"))); - SetFunctionReturnType(outputOid, CSTRINGOID); - } - else - ereport(ERROR, - (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), - errmsg("type output function %s must return type %s", - NameListToString(outputName), "cstring"))); - } - if (receiveOid) - { - resulttype = get_func_rettype(receiveOid); - if (resulttype != typoid) - ereport(ERROR, - (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), - errmsg("type receive function %s must return type %s", - NameListToString(receiveName), typeName))); - } - if (sendOid) - { - resulttype = get_func_rettype(sendOid); - if (resulttype != BYTEAOID) - ereport(ERROR, - (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), - errmsg("type send function %s must return type %s", - NameListToString(sendName), "bytea"))); - } - - /* * Convert typmodin/out function proc names to OIDs. */ if (typmodinName) @@ -1404,16 +1347,9 @@ DefineRange(CreateRangeStmt *stmt) } /* - * If it doesn't exist, create it as a shell, so that the OID is known for - * use in the range function definitions. + * Unlike DefineType(), we don't insist on a shell type existing first, as + * it's only needed if the user wants to specify a canonical function. */ - if (!OidIsValid(typoid)) - { - address = TypeShellMake(typeName, typeNamespace, GetUserId()); - typoid = address.objectId; - /* Make new shell type visible for modification below */ - CommandCounterIncrement(); - } /* Extract the parameters from the parameter list */ foreach(lc, stmt->params) @@ -1502,8 +1438,15 @@ DefineRange(CreateRangeStmt *stmt) /* Identify support functions, if provided */ if (rangeCanonicalName != NIL) + { + if (!OidIsValid(typoid)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("cannot specify a canonical function without a pre-created shell type"), + errhint("Create the type as a shell type, then create its canonicalization function, then do a full CREATE TYPE."))); rangeCanonical = findRangeCanonicalFunction(rangeCanonicalName, typoid); + } else rangeCanonical = InvalidOid; @@ -1555,7 +1498,8 @@ DefineRange(CreateRangeStmt *stmt) 0, /* Array dimensions of typbasetype */ false, /* Type NOT NULL */ InvalidOid); /* type's collation (ranges never have one) */ - Assert(typoid == address.objectId); + Assert(typoid == InvalidOid || typoid == address.objectId); + typoid = address.objectId; /* Create the entry in pg_range */ RangeCreate(typoid, rangeSubtype, rangeCollation, rangeSubOpclass, @@ -1695,63 +1639,32 @@ findTypeInputFunction(List *procname, Oid typeOid) /* * Input functions can take a single argument of type CSTRING, or three - * arguments (string, typioparam OID, typmod). - * - * For backwards compatibility we allow OPAQUE in place of CSTRING; if we - * see this, we issue a warning and fix up the pg_proc entry. + * arguments (string, typioparam OID, typmod). They must return the + * target type. */ argList[0] = CSTRINGOID; procOid = LookupFuncName(procname, 1, argList, true); - if (OidIsValid(procOid)) - return procOid; - - argList[1] = OIDOID; - argList[2] = INT4OID; - - procOid = LookupFuncName(procname, 3, argList, true); - if (OidIsValid(procOid)) - return procOid; - - /* No luck, try it with OPAQUE */ - argList[0] = OPAQUEOID; - - procOid = LookupFuncName(procname, 1, argList, true); - if (!OidIsValid(procOid)) { argList[1] = OIDOID; argList[2] = INT4OID; procOid = LookupFuncName(procname, 3, argList, true); + if (!OidIsValid(procOid)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_FUNCTION), + errmsg("function %s does not exist", + func_signature_string(procname, 1, NIL, argList)))); } - if (OidIsValid(procOid)) - { - /* Found, but must complain and fix the pg_proc entry */ - ereport(WARNING, - (errmsg("changing argument type of function %s from \"opaque\" to \"cstring\"", - NameListToString(procname)))); - SetFunctionArgType(procOid, 0, CSTRINGOID); - - /* - * Need CommandCounterIncrement since DefineType will likely try to - * alter the pg_proc tuple again. - */ - CommandCounterIncrement(); - - return procOid; - } - - /* Use CSTRING (preferred) in the error message */ - argList[0] = CSTRINGOID; - - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_FUNCTION), - errmsg("function %s does not exist", - func_signature_string(procname, 1, NIL, argList)))); + if (get_func_rettype(procOid) != typeOid) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("type input function %s must return type %s", + NameListToString(procname), format_type_be(typeOid)))); - return InvalidOid; /* keep compiler quiet */ + return procOid; } static Oid @@ -1761,48 +1674,25 @@ findTypeOutputFunction(List *procname, Oid typeOid) Oid procOid; /* - * Output functions can take a single argument of the type. - * - * For backwards compatibility we allow OPAQUE in place of the actual type - * name; if we see this, we issue a warning and fix up the pg_proc entry. + * Output functions always take a single argument of the type and return + * cstring. */ argList[0] = typeOid; procOid = LookupFuncName(procname, 1, argList, true); - if (OidIsValid(procOid)) - return procOid; - - /* No luck, try it with OPAQUE */ - argList[0] = OPAQUEOID; - - procOid = LookupFuncName(procname, 1, argList, true); - - if (OidIsValid(procOid)) - { - /* Found, but must complain and fix the pg_proc entry */ - ereport(WARNING, - (errmsg("changing argument type of function %s from \"opaque\" to %s", - NameListToString(procname), format_type_be(typeOid)))); - SetFunctionArgType(procOid, 0, typeOid); - - /* - * Need CommandCounterIncrement since DefineType will likely try to - * alter the pg_proc tuple again. - */ - CommandCounterIncrement(); - - return procOid; - } - - /* Use type name, not OPAQUE, in the failure message. */ - argList[0] = typeOid; + if (!OidIsValid(procOid)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_FUNCTION), + errmsg("function %s does not exist", + func_signature_string(procname, 1, NIL, argList)))); - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_FUNCTION), - errmsg("function %s does not exist", - func_signature_string(procname, 1, NIL, argList)))); + if (get_func_rettype(procOid) != CSTRINGOID) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("type output function %s must return type %s", + NameListToString(procname), "cstring"))); - return InvalidOid; /* keep compiler quiet */ + return procOid; } static Oid @@ -1813,27 +1703,32 @@ findTypeReceiveFunction(List *procname, Oid typeOid) /* * Receive functions can take a single argument of type INTERNAL, or three - * arguments (internal, typioparam OID, typmod). + * arguments (internal, typioparam OID, typmod). They must return the + * target type. */ argList[0] = INTERNALOID; procOid = LookupFuncName(procname, 1, argList, true); - if (OidIsValid(procOid)) - return procOid; - - argList[1] = OIDOID; - argList[2] = INT4OID; + if (!OidIsValid(procOid)) + { + argList[1] = OIDOID; + argList[2] = INT4OID; - procOid = LookupFuncName(procname, 3, argList, true); - if (OidIsValid(procOid)) - return procOid; + procOid = LookupFuncName(procname, 3, argList, true); + if (!OidIsValid(procOid)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_FUNCTION), + errmsg("function %s does not exist", + func_signature_string(procname, 1, NIL, argList)))); + } - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_FUNCTION), - errmsg("function %s does not exist", - func_signature_string(procname, 1, NIL, argList)))); + if (get_func_rettype(procOid) != typeOid) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("type receive function %s must return type %s", + NameListToString(procname), format_type_be(typeOid)))); - return InvalidOid; /* keep compiler quiet */ + return procOid; } static Oid @@ -1843,20 +1738,25 @@ findTypeSendFunction(List *procname, Oid typeOid) Oid procOid; /* - * Send functions can take a single argument of the type. + * Send functions always take a single argument of the type and return + * bytea. */ argList[0] = typeOid; procOid = LookupFuncName(procname, 1, argList, true); - if (OidIsValid(procOid)) - return procOid; + if (!OidIsValid(procOid)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_FUNCTION), + errmsg("function %s does not exist", + func_signature_string(procname, 1, NIL, argList)))); - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_FUNCTION), - errmsg("function %s does not exist", - func_signature_string(procname, 1, NIL, argList)))); + if (get_func_rettype(procOid) != BYTEAOID) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("type send function %s must return type %s", + NameListToString(procname), "bytea"))); - return InvalidOid; /* keep compiler quiet */ + return procOid; } static Oid diff --git a/src/backend/utils/adt/pseudotypes.c b/src/backend/utils/adt/pseudotypes.c index ad0e363c707..4653fc33e6d 100644 --- a/src/backend/utils/adt/pseudotypes.c +++ b/src/backend/utils/adt/pseudotypes.c @@ -415,7 +415,6 @@ PSEUDOTYPE_DUMMY_IO_FUNCS(fdw_handler); PSEUDOTYPE_DUMMY_IO_FUNCS(index_am_handler); PSEUDOTYPE_DUMMY_IO_FUNCS(tsm_handler); PSEUDOTYPE_DUMMY_IO_FUNCS(internal); -PSEUDOTYPE_DUMMY_IO_FUNCS(opaque); PSEUDOTYPE_DUMMY_IO_FUNCS(anyelement); PSEUDOTYPE_DUMMY_IO_FUNCS(anynonarray); PSEUDOTYPE_DUMMY_IO_FUNCS(table_am_handler); |