Here's what I've come up with to avoid "permission denied" errors when a
RI trigger has to lock a PK table.  Whenever the SELECT FOR UPDATE is
executed I temporarily switch the current user id to the owner of the PK
table.  It's not the grand unified solution via setuid functions that was
envisioned now and then, but it does the same conceptually.  For a
terminally elegant solution I can only suggest not using the SPI
interface.

I recommend this patch to be checked out by someone knowledgeable in the
RI area.


-- 
Peter Eisentraut      [EMAIL PROTECTED]       http://yi.org/peter-e/
*** pgsql-cvs/src/backend/utils/adt/ri_triggers.c       Tue May 30 18:10:12 2000
--- pgsql/src/backend/utils/adt/ri_triggers.c   Wed Sep 20 00:26:33 2000
***************
*** 24,29 ****
--- 24,30 ----
  #include "catalog/pg_operator.h"
  #include "commands/trigger.h"
  #include "executor/spi_priv.h"
+ #include "miscadmin.h"
  
  
  /* ----------
*************** RI_FKey_check(PG_FUNCTION_ARGS)
*** 158,163 ****
--- 159,167 ----
        bool            isnull;
        int                     i;
        int                     match_type;
+       Oid                     save_uid;
+ 
+       save_uid = GetUserId();
  
        ReferentialIntegritySnapshotOverride = true;
  
*************** RI_FKey_check(PG_FUNCTION_ARGS)
*** 252,260 ****
--- 256,268 ----
                if (SPI_connect() != SPI_OK_CONNECT)
                        elog(NOTICE, "SPI_connect() failed in RI_FKey_check()");
  
+               SetUserId(RelationGetForm(pk_rel)->relowner);
+ 
                if (SPI_execp(qplan, check_values, check_nulls, 1) != SPI_OK_SELECT)
                        elog(ERROR, "SPI_execp() failed in RI_FKey_check()");
  
+               SetUserId(save_uid);
+ 
                if (SPI_processed == 0)
                        elog(ERROR, "%s referential integrity violation - "
                                 "no rows found in %s",
*************** RI_FKey_check(PG_FUNCTION_ARGS)
*** 435,443 ****
--- 443,456 ----
         * Now check that foreign key exists in PK table
         * ----------
         */
+ 
+       SetUserId(RelationGetForm(pk_rel)->relowner);
+ 
        if (SPI_execp(qplan, check_values, check_nulls, 1) != SPI_OK_SELECT)
                elog(ERROR, "SPI_execp() failed in RI_FKey_check()");
  
+       SetUserId(save_uid);
+ 
        if (SPI_processed == 0)
                elog(ERROR, "%s referential integrity violation - "
                         "key referenced from %s not found in %s",
*************** RI_FKey_noaction_del(PG_FUNCTION_ARGS)
*** 508,513 ****
--- 521,529 ----
        char            del_nulls[RI_MAX_NUMKEYS + 1];
        bool            isnull;
        int                     i;
+       Oid         save_uid;
+ 
+       save_uid = GetUserId();
  
        ReferentialIntegritySnapshotOverride = true;
  
*************** RI_FKey_noaction_del(PG_FUNCTION_ARGS)
*** 659,667 ****
--- 675,687 ----
                         * Now check for existing references
                         * ----------
                         */
+                       SetUserId(RelationGetForm(pk_rel)->relowner);
+ 
                        if (SPI_execp(qplan, del_values, del_nulls, 1) != 
SPI_OK_SELECT)
                                elog(ERROR, "SPI_execp() failed in 
RI_FKey_noaction_del()");
  
+                       SetUserId(save_uid);
+ 
                        if (SPI_processed > 0)
                                elog(ERROR, "%s referential integrity violation - "
                                         "key in %s still referenced from %s",
*************** RI_FKey_noaction_upd(PG_FUNCTION_ARGS)
*** 716,721 ****
--- 736,744 ----
        char            upd_nulls[RI_MAX_NUMKEYS + 1];
        bool            isnull;
        int                     i;
+       Oid         save_uid;
+ 
+       save_uid = GetUserId();
  
        ReferentialIntegritySnapshotOverride = true;
  
*************** RI_FKey_noaction_upd(PG_FUNCTION_ARGS)
*** 876,884 ****
--- 899,911 ----
                         * Now check for existing references
                         * ----------
                         */
+                       SetUserId(RelationGetForm(pk_rel)->relowner);
+ 
                        if (SPI_execp(qplan, upd_values, upd_nulls, 1) != 
SPI_OK_SELECT)
                                elog(ERROR, "SPI_execp() failed in 
RI_FKey_noaction_upd()");
  
+                       SetUserId(save_uid);
+ 
                        if (SPI_processed > 0)
                                elog(ERROR, "%s referential integrity violation - "
                                         "key in %s still referenced from %s",
*************** RI_FKey_restrict_upd(PG_FUNCTION_ARGS)
*** 1570,1575 ****
--- 1597,1605 ----
        char            upd_nulls[RI_MAX_NUMKEYS + 1];
        bool            isnull;
        int                     i;
+       Oid         save_uid;
+ 
+       save_uid = GetUserId();
  
        ReferentialIntegritySnapshotOverride = true;
  
*************** RI_FKey_restrict_upd(PG_FUNCTION_ARGS)
*** 1730,1737 ****
--- 1760,1771 ----
                         * Now check for existing references
                         * ----------
                         */
+                       SetUserId(RelationGetForm(pk_rel)->relowner);
+ 
                        if (SPI_execp(qplan, upd_values, upd_nulls, 1) != 
SPI_OK_SELECT)
                                elog(ERROR, "SPI_execp() failed in 
RI_FKey_restrict_upd()");
+ 
+                       SetUserId(save_uid);
  
                        if (SPI_processed > 0)
                                elog(ERROR, "%s referential integrity violation - "

Reply via email to