diff options
Diffstat (limited to 'src/backend/commands')
-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 |
4 files changed, 99 insertions, 318 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 |