Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit baf5922

Browse files
author
Commitfest Bot
committed
[CF 5681] v2 - Prevent internal error at concurrent CREATE OR REPLACE / ALTER FUNCTION
This branch was automatically generated by a robot using patches from an email thread registered at: https://commitfest.postgresql.org/patch/5681 The branch will be overwritten each time a new patch version is posted to the thread, and also periodically to check for bitrot caused by changes on the master branch. Patch(es): https://www.postgresql.org/message-id/20250527031751.5434e5bcc383e0777b9c93eb@sraoss.co.jp Author(s): Yugo Nagata
2 parents b006bcd + acec322 commit baf5922

File tree

2 files changed

+45
-10
lines changed

2 files changed

+45
-10
lines changed

src/backend/catalog/pg_proc.c

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include "parser/parse_coerce.h"
3535
#include "pgstat.h"
3636
#include "rewrite/rewriteHandler.h"
37+
#include "storage/lmgr.h"
3738
#include "tcop/pquery.h"
3839
#include "tcop/tcopprot.h"
3940
#include "utils/acl.h"
@@ -383,24 +384,45 @@ ProcedureCreate(const char *procedureName,
383384
tupDesc = RelationGetDescr(rel);
384385

385386
/* Check for pre-existing definition */
386-
oldtup = SearchSysCache3(PROCNAMEARGSNSP,
387-
PointerGetDatum(procedureName),
388-
PointerGetDatum(parameterTypes),
389-
ObjectIdGetDatum(procNamespace));
387+
oldtup = SearchSysCacheCopy3(PROCNAMEARGSNSP,
388+
PointerGetDatum(procedureName),
389+
PointerGetDatum(parameterTypes),
390+
ObjectIdGetDatum(procNamespace));
390391

391392
if (HeapTupleIsValid(oldtup))
392393
{
393394
/* There is one; okay to replace it? */
394395
Form_pg_proc oldproc = (Form_pg_proc) GETSTRUCT(oldtup);
395-
Datum proargnames;
396-
bool isnull;
397-
const char *dropcmd;
398396

399397
if (!replace)
400398
ereport(ERROR,
401399
(errcode(ERRCODE_DUPLICATE_FUNCTION),
402400
errmsg("function \"%s\" already exists with same argument types",
403401
procedureName)));
402+
403+
/* Lock the function so nobody else can do anything with it. */
404+
LockDatabaseObject(ProcedureRelationId, oldproc->oid, 0, AccessExclusiveLock);
405+
406+
/*
407+
* It is possible that by the time we acquire the lock on function,
408+
* concurrent DDL has removed it. We can test this by checking the
409+
* existence of function. We get the tuple again to avoid the risk
410+
* of function definition getting changed.
411+
*/
412+
oldtup = SearchSysCacheCopy3(PROCNAMEARGSNSP,
413+
PointerGetDatum(procedureName),
414+
PointerGetDatum(parameterTypes),
415+
ObjectIdGetDatum(procNamespace));
416+
}
417+
418+
if (HeapTupleIsValid(oldtup))
419+
{
420+
421+
Form_pg_proc oldproc = (Form_pg_proc) GETSTRUCT(oldtup);
422+
Datum proargnames;
423+
bool isnull;
424+
const char *dropcmd;
425+
404426
if (!object_ownercheck(ProcedureRelationId, oldproc->oid, proowner))
405427
aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_FUNCTION,
406428
procedureName);
@@ -585,7 +607,7 @@ ProcedureCreate(const char *procedureName,
585607
tup = heap_modify_tuple(oldtup, tupDesc, values, nulls, replaces);
586608
CatalogTupleUpdate(rel, &tup->t_self, tup);
587609

588-
ReleaseSysCache(oldtup);
610+
heap_freetuple(oldtup);
589611
is_update = true;
590612
}
591613
else

src/backend/commands/functioncmds.c

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
#include "parser/parse_func.h"
6262
#include "parser/parse_type.h"
6363
#include "pgstat.h"
64+
#include "storage/lmgr.h"
6465
#include "tcop/pquery.h"
6566
#include "tcop/utility.h"
6667
#include "utils/acl.h"
@@ -1383,9 +1384,21 @@ AlterFunction(ParseState *pstate, AlterFunctionStmt *stmt)
13831384

13841385
ObjectAddressSet(address, ProcedureRelationId, funcOid);
13851386

1387+
/* Lock the function so nobody else can do anything with it. */
1388+
LockDatabaseObject(ProcedureRelationId, funcOid, 0, AccessExclusiveLock);
1389+
1390+
/*
1391+
* It is possible that by the time we acquire the lock on function,
1392+
* concurrent DDL has removed it. We can test this by checking the
1393+
* existence of function. We get the tuple again to avoid the risk
1394+
* of function definition getting changed.
1395+
*/
13861396
tup = SearchSysCacheCopy1(PROCOID, ObjectIdGetDatum(funcOid));
1387-
if (!HeapTupleIsValid(tup)) /* should not happen */
1388-
elog(ERROR, "cache lookup failed for function %u", funcOid);
1397+
if (!HeapTupleIsValid(tup))
1398+
ereport(ERROR,
1399+
errcode(ERRCODE_UNDEFINED_OBJECT),
1400+
errmsg("function \"%s\" does not exist",
1401+
NameListToString(stmt->func->objname)));
13891402

13901403
procForm = (Form_pg_proc) GETSTRUCT(tup);
13911404

0 commit comments

Comments
 (0)