Re: [EXAMPLE] Overly zealous security of schemas... - Mailing list pgsql-hackers

From Tom Lane
Subject Re: [EXAMPLE] Overly zealous security of schemas...
Date
Msg-id 21461.1051395858@sss.pgh.pa.us
Whole thread Raw
In response to Re: [EXAMPLE] Overly zealous security of schemas...  (Sean Chittenden <sean@chittenden.org>)
Responses Re: [EXAMPLE] Overly zealous security of schemas...  (Sean Chittenden <sean@chittenden.org>)
List pgsql-hackers
Sean Chittenden <sean@chittenden.org> writes:
> Ah, I had this backwards: I thought SECURITY DEFINER wasn't setting
> something that'd allow the foreign keys to run as the owner of the
> function.

Nah; by the time the RI triggers run, you're out of the function
entirely.  So they have to fend for themselves.

Here's the 7.3 version of the patch (it's a bit ugly because I had to
back-port a couple of changes that are in CVS tip).
        regards, tom lane


*** src/backend/utils/adt/ri_triggers.c.orig    Thu Mar 27 14:25:52 2003
--- src/backend/utils/adt/ri_triggers.c    Sat Apr 26 18:12:16 2003
***************
*** 58,74 **** #define RI_KEYS_SOME_NULL                1 #define RI_KEYS_NONE_NULL                2 
!  #define RI_PLAN_CHECK_LOOKUPPK_NOCOLS    1 #define RI_PLAN_CHECK_LOOKUPPK            2
! #define RI_PLAN_CASCADE_DEL_DODELETE    1
! #define RI_PLAN_CASCADE_UPD_DOUPDATE    1
! #define RI_PLAN_NOACTION_DEL_CHECKREF    1
! #define RI_PLAN_NOACTION_UPD_CHECKREF    1
! #define RI_PLAN_RESTRICT_DEL_CHECKREF    1
! #define RI_PLAN_RESTRICT_UPD_CHECKREF    1
! #define RI_PLAN_SETNULL_DEL_DOUPDATE    1
! #define RI_PLAN_SETNULL_UPD_DOUPDATE    1  #define MAX_QUOTED_NAME_LEN  (NAMEDATALEN*2+3) #define
MAX_QUOTED_REL_NAME_LEN (MAX_QUOTED_NAME_LEN*2)
 
--- 58,75 ---- #define RI_KEYS_SOME_NULL                1 #define RI_KEYS_NONE_NULL                2 
! /* queryno values must be distinct for the convenience of ri_PerformCheck */ #define RI_PLAN_CHECK_LOOKUPPK_NOCOLS
1#define RI_PLAN_CHECK_LOOKUPPK            2
 
! #define RI_PLAN_CASCADE_DEL_DODELETE    3
! #define RI_PLAN_CASCADE_UPD_DOUPDATE    4
! #define RI_PLAN_NOACTION_DEL_CHECKREF    5
! #define RI_PLAN_NOACTION_UPD_CHECKREF    6
! #define RI_PLAN_RESTRICT_DEL_CHECKREF    7
! #define RI_PLAN_RESTRICT_UPD_CHECKREF    8
! #define RI_PLAN_SETNULL_DEL_DOUPDATE    9
! #define RI_PLAN_SETNULL_UPD_DOUPDATE    10
! #define RI_PLAN_KEYEQUAL_UPD            11  #define MAX_QUOTED_NAME_LEN  (NAMEDATALEN*2+3) #define
MAX_QUOTED_REL_NAME_LEN (MAX_QUOTED_NAME_LEN*2)
 
***************
*** 149,154 ****
--- 150,159 ---- static void ri_InitHashTables(void); static void *ri_FetchPreparedPlan(RI_QueryKey *key); static void
ri_HashPreparedPlan(RI_QueryKey*key, void *plan);
 
+ static void *ri_PlanCheck(char *querystr, int nargs, Oid *argtypes,
+                           RI_QueryKey *qkey, Relation fk_rel, Relation pk_rel,
+                           bool cache_plan);
+   /* ----------  * RI_FKey_check -
***************
*** 264,269 ****
--- 269,277 ----                              fk_rel, pk_rel,                              tgnargs, tgargs); 
+         if (SPI_connect() != SPI_OK_CONNECT)
+             elog(ERROR, "SPI_connect() failed in RI_FKey_check()");
+          if ((qplan = ri_FetchPreparedPlan(&qkey)) == NULL)         {             char
querystr[MAX_QUOTED_REL_NAME_LEN+ 100];
 
***************
*** 278,297 ****             snprintf(querystr, sizeof(querystr), "SELECT 1 FROM ONLY %s x FOR UPDATE OF x",
         pkrelname); 
 
!             /*
!              * Prepare, save and remember the new plan.
!              */
!             qplan = SPI_prepare(querystr, 0, NULL);
!             qplan = SPI_saveplan(qplan);
!             ri_HashPreparedPlan(&qkey, qplan);         }          /*          * Execute the plan          */
-         if (SPI_connect() != SPI_OK_CONNECT)
-             elog(WARNING, "SPI_connect() failed in RI_FKey_check()");
-          SetUserId(RelationGetForm(pk_rel)->relowner);          if (SPI_execp(qplan, check_values, check_nulls, 1) !=
SPI_OK_SELECT)
--- 286,299 ----             snprintf(querystr, sizeof(querystr), "SELECT 1 FROM ONLY %s x FOR UPDATE OF x",
         pkrelname); 
 
!             /* Prepare and save the plan */
!             qplan = ri_PlanCheck(querystr, 0, NULL,
!                                  &qkey, fk_rel, pk_rel, true);         }          /*          * Execute the plan
   */         SetUserId(RelationGetForm(pk_rel)->relowner);          if (SPI_execp(qplan, check_values, check_nulls, 1)
!=SPI_OK_SELECT)
 
***************
*** 420,426 ****          * The query string built is          *    SELECT 1 FROM ONLY <pktable> WHERE pkatt1 = $1 [AND
...]         * The type id's for the $ parameters are those of the
 
!          * corresponding FK attributes. Thus, SPI_prepare could          * eventually fail if the parser cannot
identifysome way          * how to compare these two types by '='.          * ----------
 
--- 422,428 ----          * The query string built is          *    SELECT 1 FROM ONLY <pktable> WHERE pkatt1 = $1 [AND
...]         * The type id's for the $ parameters are those of the
 
!          * corresponding FK attributes. Thus, ri_PlanCheck could          * eventually fail if the parser cannot
identifysome way          * how to compare these two types by '='.          * ----------
 
***************
*** 440,451 ****         }         strcat(querystr, " FOR UPDATE OF x"); 
!         /*
!          * Prepare, save and remember the new plan.
!          */
!         qplan = SPI_prepare(querystr, qkey.nkeypairs, queryoids);
!         qplan = SPI_saveplan(qplan);
!         ri_HashPreparedPlan(&qkey, qplan);     }      /*
--- 442,450 ----         }         strcat(querystr, " FOR UPDATE OF x"); 
!         /* Prepare and save the plan */
!         qplan = ri_PlanCheck(querystr, qkey.nkeypairs, queryoids,
!                              &qkey, fk_rel, pk_rel, true);     }      /*
***************
*** 625,631 ****          * The query string built is          *    SELECT 1 FROM ONLY <pktable> WHERE pkatt1 = $1 [AND
...]         * The type id's for the $ parameters are those of the
 
!          * corresponding FK attributes. Thus, SPI_prepare could          * eventually fail if the parser cannot
identifysome way          * how to compare these two types by '='.          * ----------
 
--- 624,630 ----          * The query string built is          *    SELECT 1 FROM ONLY <pktable> WHERE pkatt1 = $1 [AND
...]         * The type id's for the $ parameters are those of the
 
!          * corresponding FK attributes. Thus, ri_PlanCheck could          * eventually fail if the parser cannot
identifysome way          * how to compare these two types by '='.          * ----------
 
***************
*** 645,656 ****         }         strcat(querystr, " FOR UPDATE OF x"); 
!         /*
!          * Prepare, save and remember the new plan.
!          */
!         qplan = SPI_prepare(querystr, qkey.nkeypairs, queryoids);
!         qplan = SPI_saveplan(qplan);
!         ri_HashPreparedPlan(&qkey, qplan);     }      /*
--- 644,652 ----         }         strcat(querystr, " FOR UPDATE OF x"); 
!         /* Prepare and save the plan */
!         qplan = ri_PlanCheck(querystr, qkey.nkeypairs, queryoids,
!                              &qkey, pk_rel, pk_rel, true);     }      /*
***************
*** 834,840 ****                  * The query string built is                  *    SELECT 1 FROM ONLY <fktable> WHERE
fkatt1= $1 [AND ...]                  * The type id's for the $ parameters are those of the
 
!                  * corresponding PK attributes. Thus, SPI_prepare could                  * eventually fail if the
parsercannot identify some way                  * how to compare these two types by '='.                  * ----------
 
--- 830,836 ----                  * The query string built is                  *    SELECT 1 FROM ONLY <fktable> WHERE
fkatt1= $1 [AND ...]                  * The type id's for the $ parameters are those of the
 
!                  * corresponding PK attributes. Thus, ri_PlanCheck could                  * eventually fail if the
parsercannot identify some way                  * how to compare these two types by '='.                  * ----------
 
***************
*** 854,865 ****                 }                 strcat(querystr, " FOR UPDATE OF x"); 
!                 /*
!                  * Prepare, save and remember the new plan.
!                  */
!                 qplan = SPI_prepare(querystr, qkey.nkeypairs, queryoids);
!                 qplan = SPI_saveplan(qplan);
!                 ri_HashPreparedPlan(&qkey, qplan);             }              /*
--- 850,858 ----                 }                 strcat(querystr, " FOR UPDATE OF x"); 
!                 /* Prepare and save the plan */
!                 qplan = ri_PlanCheck(querystr, qkey.nkeypairs, queryoids,
!                                      &qkey, fk_rel, pk_rel, true);             }              /*
***************
*** 1075,1081 ****                  * The query string built is                  *    SELECT 1 FROM ONLY <fktable>
WHEREfkatt1 = $1 [AND ...]                  * The type id's for the $ parameters are those of the
 
!                  * corresponding PK attributes. Thus, SPI_prepare could                  * eventually fail if the
parsercannot identify some way                  * how to compare these two types by '='.                  * ----------
 
--- 1068,1074 ----                  * The query string built is                  *    SELECT 1 FROM ONLY <fktable>
WHEREfkatt1 = $1 [AND ...]                  * The type id's for the $ parameters are those of the
 
!                  * corresponding PK attributes. Thus, ri_PlanCheck could                  * eventually fail if the
parsercannot identify some way                  * how to compare these two types by '='.                  * ----------
 
***************
*** 1095,1106 ****                 }                 strcat(querystr, " FOR UPDATE OF x"); 
!                 /*
!                  * Prepare, save and remember the new plan.
!                  */
!                 qplan = SPI_prepare(querystr, qkey.nkeypairs, queryoids);
!                 qplan = SPI_saveplan(qplan);
!                 ri_HashPreparedPlan(&qkey, qplan);             }              /*
--- 1088,1096 ----                 }                 strcat(querystr, " FOR UPDATE OF x"); 
!                 /* Prepare and save the plan */
!                 qplan = ri_PlanCheck(querystr, qkey.nkeypairs, queryoids,
!                                      &qkey, fk_rel, pk_rel, true);             }              /*
***************
*** 1288,1294 ****                  * The query string built is                  *    DELETE FROM ONLY <fktable> WHERE
fkatt1= $1 [AND ...]                  * The type id's for the $ parameters are those of the
 
!                  * corresponding PK attributes. Thus, SPI_prepare could                  * eventually fail if the
parsercannot identify some way                  * how to compare these two types by '='.                  * ----------
 
--- 1278,1284 ----                  * The query string built is                  *    DELETE FROM ONLY <fktable> WHERE
fkatt1= $1 [AND ...]                  * The type id's for the $ parameters are those of the
 
!                  * corresponding PK attributes. Thus, ri_PlanCheck could                  * eventually fail if the
parsercannot identify some way                  * how to compare these two types by '='.                  * ----------
 
***************
*** 1307,1318 ****                                      qkey.keypair[i][RI_KEYPAIR_PK_IDX]);                 } 
!                 /*
!                  * Prepare, save and remember the new plan.
!                  */
!                 qplan = SPI_prepare(querystr, qkey.nkeypairs, queryoids);
!                 qplan = SPI_saveplan(qplan);
!                 ri_HashPreparedPlan(&qkey, qplan);             }              /*
--- 1297,1305 ----                                      qkey.keypair[i][RI_KEYPAIR_PK_IDX]);                 } 
!                 /* Prepare and save the plan */
!                 qplan = ri_PlanCheck(querystr, qkey.nkeypairs, queryoids,
!                                      &qkey, fk_rel, pk_rel, true);             }              /*
***************
*** 1511,1517 ****                  *    UPDATE ONLY <fktable> SET fkatt1 = $1 [, ...]                  *
WHEREfkatt1 = $n [AND ...]                  * The type id's for the $ parameters are those of the
 
!                  * corresponding PK attributes. Thus, SPI_prepare could                  * eventually fail if the
parsercannot identify some way                  * how to compare these two types by '='.                  * ----------
 
--- 1498,1504 ----                  *    UPDATE ONLY <fktable> SET fkatt1 = $1 [, ...]                  *
WHEREfkatt1 = $n [AND ...]                  * The type id's for the $ parameters are those of the
 
!                  * corresponding PK attributes. Thus, ri_PlanCheck could                  * eventually fail if the
parsercannot identify some way                  * how to compare these two types by '='.                  * ----------
 
***************
*** 1537,1548 ****                 }                 strcat(querystr, qualstr); 
!                 /*
!                  * Prepare, save and remember the new plan.
!                  */
!                 qplan = SPI_prepare(querystr, qkey.nkeypairs * 2, queryoids);
!                 qplan = SPI_saveplan(qplan);
!                 ri_HashPreparedPlan(&qkey, qplan);             }              /*
--- 1524,1532 ----                 }                 strcat(querystr, qualstr); 
!                 /* Prepare and save the plan */
!                 qplan = ri_PlanCheck(querystr, qkey.nkeypairs * 2, queryoids,
!                                      &qkey, fk_rel, pk_rel, true);             }              /*
***************
*** 1741,1747 ****                  * The query string built is                  *    SELECT 1 FROM ONLY <fktable>
WHEREfkatt1 = $1 [AND ...]                  * The type id's for the $ parameters are those of the
 
!                  * corresponding PK attributes. Thus, SPI_prepare could                  * eventually fail if the
parsercannot identify some way                  * how to compare these two types by '='.                  * ----------
 
--- 1725,1731 ----                  * The query string built is                  *    SELECT 1 FROM ONLY <fktable>
WHEREfkatt1 = $1 [AND ...]                  * The type id's for the $ parameters are those of the
 
!                  * corresponding PK attributes. Thus, ri_PlanCheck could                  * eventually fail if the
parsercannot identify some way                  * how to compare these two types by '='.                  * ----------
 
***************
*** 1761,1772 ****                 }                 strcat(querystr, " FOR UPDATE OF x"); 
!                 /*
!                  * Prepare, save and remember the new plan.
!                  */
!                 qplan = SPI_prepare(querystr, qkey.nkeypairs, queryoids);
!                 qplan = SPI_saveplan(qplan);
!                 ri_HashPreparedPlan(&qkey, qplan);             }              /*
--- 1745,1753 ----                 }                 strcat(querystr, " FOR UPDATE OF x"); 
!                 /* Prepare and save the plan */
!                 qplan = ri_PlanCheck(querystr, qkey.nkeypairs, queryoids,
!                                      &qkey, fk_rel, pk_rel, true);             }              /*
***************
*** 1975,1981 ****                  * The query string built is                  *    SELECT 1 FROM ONLY <fktable>
WHEREfkatt1 = $1 [AND ...]                  * The type id's for the $ parameters are those of the
 
!                  * corresponding PK attributes. Thus, SPI_prepare could                  * eventually fail if the
parsercannot identify some way                  * how to compare these two types by '='.                  * ----------
 
--- 1956,1962 ----                  * The query string built is                  *    SELECT 1 FROM ONLY <fktable>
WHEREfkatt1 = $1 [AND ...]                  * The type id's for the $ parameters are those of the
 
!                  * corresponding PK attributes. Thus, ri_PlanCheck could                  * eventually fail if the
parsercannot identify some way                  * how to compare these two types by '='.                  * ----------
 
***************
*** 1995,2006 ****                 }                 strcat(querystr, " FOR UPDATE OF x"); 
!                 /*
!                  * Prepare, save and remember the new plan.
!                  */
!                 qplan = SPI_prepare(querystr, qkey.nkeypairs, queryoids);
!                 qplan = SPI_saveplan(qplan);
!                 ri_HashPreparedPlan(&qkey, qplan);             }              /*
--- 1976,1984 ----                 }                 strcat(querystr, " FOR UPDATE OF x"); 
!                 /* Prepare and save the plan */
!                 qplan = ri_PlanCheck(querystr, qkey.nkeypairs, queryoids,
!                                      &qkey, fk_rel, pk_rel, true);             }              /*
***************
*** 2195,2201 ****                  *    UPDATE ONLY <fktable> SET fkatt1 = NULL [, ...]                  *
WHEREfkatt1 = $1 [AND ...]                  * The type id's for the $ parameters are those of the
 
!                  * corresponding PK attributes. Thus, SPI_prepare could                  * eventually fail if the
parsercannot identify some way                  * how to compare these two types by '='.                  * ----------
 
--- 2173,2179 ----                  *    UPDATE ONLY <fktable> SET fkatt1 = NULL [, ...]                  *
WHEREfkatt1 = $1 [AND ...]                  * The type id's for the $ parameters are those of the
 
!                  * corresponding PK attributes. Thus, ri_PlanCheck could                  * eventually fail if the
parsercannot identify some way                  * how to compare these two types by '='.                  * ----------
 
***************
*** 2220,2231 ****                 }                 strcat(querystr, qualstr); 
!                 /*
!                  * Prepare, save and remember the new plan.
!                  */
!                 qplan = SPI_prepare(querystr, qkey.nkeypairs, queryoids);
!                 qplan = SPI_saveplan(qplan);
!                 ri_HashPreparedPlan(&qkey, qplan);             }              /*
--- 2198,2206 ----                 }                 strcat(querystr, qualstr); 
!                 /* Prepare and save the plan */
!                 qplan = ri_PlanCheck(querystr, qkey.nkeypairs, queryoids,
!                                      &qkey, fk_rel, pk_rel, true);             }              /*
***************
*** 2445,2451 ****                  *    UPDATE ONLY <fktable> SET fkatt1 = NULL [, ...]                  *
WHEREfkatt1 = $1 [AND ...]                  * The type id's for the $ parameters are those of the
 
!                  * corresponding PK attributes. Thus, SPI_prepare could                  * eventually fail if the
parsercannot identify some way                  * how to compare these two types by '='.                  * ----------
 
--- 2420,2426 ----                  *    UPDATE ONLY <fktable> SET fkatt1 = NULL [, ...]                  *
WHEREfkatt1 = $1 [AND ...]                  * The type id's for the $ parameters are those of the 
!                  * corresponding PK attributes. Thus, ri_PlanCheck could                  * eventually fail if the
parsercannot identify some way                  * how to compare these two types by '='.                  * ----------
 
***************
*** 2481,2499 ****                 strcat(querystr, qualstr);                  /*
!                  * Prepare the new plan.
!                  */
!                 qplan = SPI_prepare(querystr, qkey.nkeypairs, queryoids);
! 
!                 /*
!                  * Save and remember the plan if we're building the                  * "standard" plan.
  */
 
!                 if (use_cached_query)
!                 {
!                     qplan = SPI_saveplan(qplan);
!                     ri_HashPreparedPlan(&qkey, qplan);
!                 }             }              /*
--- 2456,2467 ----                 strcat(querystr, qualstr);                  /*
!                  * Prepare the plan.  Save it only if we're building the                  * "standard" plan.
       */
 
!                 qplan = ri_PlanCheck(querystr, qkey.nkeypairs, queryoids,
!                                      &qkey, fk_rel, pk_rel,
!                                      use_cached_query);             }              /*
***************
*** 2682,2688 ****                  *    UPDATE ONLY <fktable> SET fkatt1 = NULL [, ...]                  *
WHEREfkatt1 = $1 [AND ...]                  * The type id's for the $ parameters are those of the
 
!                  * corresponding PK attributes. Thus, SPI_prepare could                  * eventually fail if the
parsercannot identify some way                  * how to compare these two types by '='.                  * ----------
 
--- 2650,2656 ----                  *    UPDATE ONLY <fktable> SET fkatt1 = NULL [, ...]                  *
WHEREfkatt1 = $1 [AND ...]                  * The type id's for the $ parameters are those of the
 
!                  * corresponding PK attributes. Thus, ri_PlanCheck could                  * eventually fail if the
parsercannot identify some way                  * how to compare these two types by '='.                  * ----------
 
***************
*** 2707,2716 ****                 }                 strcat(querystr, qualstr); 
!                 /*
!                  * Prepare the plan
!                  */
!                 qplan = SPI_prepare(querystr, qkey.nkeypairs, queryoids);                  /*                  * Scan
theplan's targetlist and replace the NULLs by
 
--- 2675,2683 ----                 }                 strcat(querystr, qualstr); 
!                 /* Prepare the plan, don't save it */
!                 qplan = ri_PlanCheck(querystr, qkey.nkeypairs, queryoids,
!                                      &qkey, fk_rel, pk_rel, false);                  /*                  * Scan the
plan'stargetlist and replace the NULLs by
 
***************
*** 2942,2948 ****                  *    UPDATE ONLY <fktable> SET fkatt1 = NULL [, ...]                  *
WHEREfkatt1 = $1 [AND ...]                  * The type id's for the $ parameters are those of the
 
!                  * corresponding PK attributes. Thus, SPI_prepare could                  * eventually fail if the
parsercannot identify some way                  * how to compare these two types by '='.                  * ----------
 
--- 2909,2915 ----                  *    UPDATE ONLY <fktable> SET fkatt1 = NULL [, ...]                  *
WHEREfkatt1 = $1 [AND ...]                  * The type id's for the $ parameters are those of the
 
!                  * corresponding PK attributes. Thus, ri_PlanCheck could                  * eventually fail if the
parsercannot identify some way                  * how to compare these two types by '='.                  * ----------
 
***************
*** 2977,2986 ****                 }                 strcat(querystr, qualstr); 
!                 /*
!                  * Prepare the plan
!                  */
!                 qplan = SPI_prepare(querystr, qkey.nkeypairs, queryoids);                  /*                  * Scan
theplan's targetlist and replace the NULLs by
 
--- 2944,2952 ----                 }                 strcat(querystr, qualstr); 
!                 /* Prepare the plan, don't save it */
!                 qplan = ri_PlanCheck(querystr, qkey.nkeypairs, queryoids,
!                                      &qkey, fk_rel, pk_rel, false);                  /*                  * Scan the
plan'stargetlist and replace the NULLs by
 
***************
*** 3124,3130 ****         case RI_MATCH_TYPE_UNSPECIFIED:         case RI_MATCH_TYPE_FULL:
ri_BuildQueryKeyFull(&qkey,trigdata->tg_trigger->tgoid,
 
!                                  0,                                  fk_rel, pk_rel,
tgnargs,tgargs); 
 
--- 3090,3096 ----         case RI_MATCH_TYPE_UNSPECIFIED:         case RI_MATCH_TYPE_FULL:
ri_BuildQueryKeyFull(&qkey,trigdata->tg_trigger->tgoid,
 
!                                  RI_PLAN_KEYEQUAL_UPD,                                  fk_rel, pk_rel,
                  tgnargs, tgargs); 
 
***************
*** 3160,3165 ****
--- 3126,3177 ----  * ----------  */ 
+ 
+ /*
+  * Prepare execution plan for a query to enforce an RI restriction
+  *
+  * If cache_plan is true, the plan is saved into our plan hashtable
+  * so that we don't need to plan it again.
+  */
+ static void *
+ ri_PlanCheck(char *querystr, int nargs, Oid *argtypes,
+              RI_QueryKey *qkey, Relation fk_rel, Relation pk_rel,
+              bool cache_plan)
+ {
+     void       *qplan;
+     Relation    query_rel;
+     Oid            save_uid;
+ 
+     /*
+      * The query is always run against the FK table except
+      * when this is an update/insert trigger on the FK table itself -
+      * either RI_PLAN_CHECK_LOOKUPPK or RI_PLAN_CHECK_LOOKUPPK_NOCOLS
+      */
+     if (qkey->constr_queryno == RI_PLAN_CHECK_LOOKUPPK ||
+         qkey->constr_queryno == RI_PLAN_CHECK_LOOKUPPK_NOCOLS)
+         query_rel = pk_rel;
+     else
+         query_rel = fk_rel;
+ 
+     /* Switch to proper UID to perform check as */
+     save_uid = GetUserId();
+     SetUserId(RelationGetForm(query_rel)->relowner);
+ 
+     /* Create the plan */
+     qplan = SPI_prepare(querystr, nargs, argtypes);
+ 
+     /* Restore UID */
+     SetUserId(save_uid);
+ 
+     /* Save the plan if requested */
+     if (cache_plan)
+     {
+         qplan = SPI_saveplan(qplan);
+         ri_HashPreparedPlan(qkey, qplan);
+     }
+ 
+     return qplan;
+ }  /*  * quoteOneName --- safely quote a single SQL name



pgsql-hackers by date:

Previous
From: Sean Chittenden
Date:
Subject: Re: [EXAMPLE] Overly zealous security of schemas...
Next
From: Tom Lane
Date:
Subject: Re: [EXAMPLE] Overly zealous security of schemas...