|
34 | 34 | #include "parser/parse_coerce.h"
|
35 | 35 | #include "pgstat.h"
|
36 | 36 | #include "rewrite/rewriteHandler.h"
|
| 37 | +#include "storage/lmgr.h" |
37 | 38 | #include "tcop/pquery.h"
|
38 | 39 | #include "tcop/tcopprot.h"
|
39 | 40 | #include "utils/acl.h"
|
@@ -383,24 +384,45 @@ ProcedureCreate(const char *procedureName,
|
383 | 384 | tupDesc = RelationGetDescr(rel);
|
384 | 385 |
|
385 | 386 | /* 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)); |
390 | 391 |
|
391 | 392 | if (HeapTupleIsValid(oldtup))
|
392 | 393 | {
|
393 | 394 | /* There is one; okay to replace it? */
|
394 | 395 | Form_pg_proc oldproc = (Form_pg_proc) GETSTRUCT(oldtup);
|
395 |
| - Datum proargnames; |
396 |
| - bool isnull; |
397 |
| - const char *dropcmd; |
398 | 396 |
|
399 | 397 | if (!replace)
|
400 | 398 | ereport(ERROR,
|
401 | 399 | (errcode(ERRCODE_DUPLICATE_FUNCTION),
|
402 | 400 | errmsg("function \"%s\" already exists with same argument types",
|
403 | 401 | 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 | + |
404 | 426 | if (!object_ownercheck(ProcedureRelationId, oldproc->oid, proowner))
|
405 | 427 | aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_FUNCTION,
|
406 | 428 | procedureName);
|
@@ -585,7 +607,7 @@ ProcedureCreate(const char *procedureName,
|
585 | 607 | tup = heap_modify_tuple(oldtup, tupDesc, values, nulls, replaces);
|
586 | 608 | CatalogTupleUpdate(rel, &tup->t_self, tup);
|
587 | 609 |
|
588 |
| - ReleaseSysCache(oldtup); |
| 610 | + heap_freetuple(oldtup); |
589 | 611 | is_update = true;
|
590 | 612 | }
|
591 | 613 | else
|
|
0 commit comments