aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/execMain.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor/execMain.c')
-rw-r--r--src/backend/executor/execMain.c120
1 files changed, 59 insertions, 61 deletions
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 9d64c979e08..a340477c47a 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -26,7 +26,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.226 2004/01/10 23:28:44 neilc Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.227 2004/01/14 23:01:54 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -86,8 +86,8 @@ static void ExecUpdate(TupleTableSlot *slot, ItemPointer tupleid,
EState *estate);
static TupleTableSlot *EvalPlanQualNext(EState *estate);
static void EndEvalPlanQual(EState *estate);
-static void ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation);
-static void ExecCheckXactReadOnly(Query *parsetree, CmdType operation);
+static void ExecCheckRTEPerms(RangeTblEntry *rte);
+static void ExecCheckXactReadOnly(Query *parsetree);
static void EvalPlanQualStart(evalPlanQual *epq, EState *estate,
evalPlanQual *priorepq);
static void EvalPlanQualStop(evalPlanQual *epq);
@@ -136,8 +136,8 @@ ExecutorStart(QueryDesc *queryDesc, bool useCurrentSnapshot, bool explainOnly)
* If the transaction is read-only, we need to check if any writes are
* planned to non-temporary tables.
*/
- if (!explainOnly)
- ExecCheckXactReadOnly(queryDesc->parsetree, queryDesc->operation);
+ if (XactReadOnly && !explainOnly)
+ ExecCheckXactReadOnly(queryDesc->parsetree);
/*
* Build EState, switch into per-query memory context for startup.
@@ -351,7 +351,7 @@ ExecutorRewind(QueryDesc *queryDesc)
* Check access permissions for all relations listed in a range table.
*/
void
-ExecCheckRTPerms(List *rangeTable, CmdType operation)
+ExecCheckRTPerms(List *rangeTable)
{
List *lp;
@@ -359,7 +359,7 @@ ExecCheckRTPerms(List *rangeTable, CmdType operation)
{
RangeTblEntry *rte = lfirst(lp);
- ExecCheckRTEPerms(rte, operation);
+ ExecCheckRTEPerms(rte);
}
}
@@ -368,18 +368,18 @@ ExecCheckRTPerms(List *rangeTable, CmdType operation)
* Check access permissions for a single RTE.
*/
static void
-ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation)
+ExecCheckRTEPerms(RangeTblEntry *rte)
{
+ AclMode requiredPerms;
Oid relOid;
AclId userid;
- AclResult aclcheck_result;
/*
* If it's a subquery, recursively examine its rangetable.
*/
if (rte->rtekind == RTE_SUBQUERY)
{
- ExecCheckRTPerms(rte->subquery->rtable, operation);
+ ExecCheckRTPerms(rte->subquery->rtable);
return;
}
@@ -391,6 +391,13 @@ ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation)
if (rte->rtekind != RTE_RELATION)
return;
+ /*
+ * No work if requiredPerms is empty.
+ */
+ requiredPerms = rte->requiredPerms;
+ if (requiredPerms == 0)
+ return;
+
relOid = rte->relid;
/*
@@ -404,77 +411,68 @@ ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation)
*/
userid = rte->checkAsUser ? rte->checkAsUser : GetUserId();
-#define CHECK(MODE) pg_class_aclcheck(relOid, userid, MODE)
+ /*
+ * For each bit in requiredPerms, apply the required check. (We can't
+ * do this in one aclcheck call because aclcheck treats multiple bits
+ * as OR semantics, when we want AND.)
+ *
+ * We use a well-known cute trick for isolating the rightmost one-bit
+ * in a nonzero word. See nodes/bitmapset.c for commentary.
+ */
+#define RIGHTMOST_ONE(x) ((int32) (x) & -((int32) (x)))
- if (rte->checkForRead)
+ while (requiredPerms != 0)
{
- aclcheck_result = CHECK(ACL_SELECT);
- if (aclcheck_result != ACLCHECK_OK)
- aclcheck_error(aclcheck_result, ACL_KIND_CLASS,
- get_rel_name(relOid));
- }
+ AclMode thisPerm;
+ AclResult aclcheck_result;
- if (rte->checkForWrite)
- {
- /*
- * Note: write access in a SELECT context means SELECT FOR UPDATE.
- * Right now we don't distinguish that from true update as far as
- * permissions checks are concerned.
- */
- switch (operation)
- {
- case CMD_INSERT:
- aclcheck_result = CHECK(ACL_INSERT);
- break;
- case CMD_SELECT:
- case CMD_UPDATE:
- aclcheck_result = CHECK(ACL_UPDATE);
- break;
- case CMD_DELETE:
- aclcheck_result = CHECK(ACL_DELETE);
- break;
- default:
- elog(ERROR, "unrecognized operation code: %d",
- (int) operation);
- aclcheck_result = ACLCHECK_OK; /* keep compiler quiet */
- break;
- }
+ thisPerm = RIGHTMOST_ONE(requiredPerms);
+ requiredPerms &= ~thisPerm;
+
+ aclcheck_result = pg_class_aclcheck(relOid, userid, thisPerm);
if (aclcheck_result != ACLCHECK_OK)
aclcheck_error(aclcheck_result, ACL_KIND_CLASS,
get_rel_name(relOid));
}
}
+/*
+ * Check that the query does not imply any writes to non-temp tables.
+ */
static void
-ExecCheckXactReadOnly(Query *parsetree, CmdType operation)
+ExecCheckXactReadOnly(Query *parsetree)
{
- if (!XactReadOnly)
- return;
+ List *lp;
- /* CREATE TABLE AS or SELECT INTO */
- if (operation == CMD_SELECT && parsetree->into != NULL)
+ /*
+ * CREATE TABLE AS or SELECT INTO?
+ *
+ * XXX should we allow this if the destination is temp?
+ */
+ if (parsetree->into != NULL)
goto fail;
- if (operation == CMD_DELETE || operation == CMD_INSERT
- || operation == CMD_UPDATE)
+ /* Fail if write permissions are requested on any non-temp table */
+ foreach(lp, parsetree->rtable)
{
- List *lp;
+ RangeTblEntry *rte = lfirst(lp);
- foreach(lp, parsetree->rtable)
+ if (rte->rtekind == RTE_SUBQUERY)
{
- RangeTblEntry *rte = lfirst(lp);
+ ExecCheckXactReadOnly(rte->subquery);
+ continue;
+ }
- if (rte->rtekind != RTE_RELATION)
- continue;
+ if (rte->rtekind != RTE_RELATION)
+ continue;
- if (!rte->checkForWrite)
- continue;
+ if ((rte->requiredPerms & (~ACL_SELECT)) == 0)
+ continue;
- if (isTempNamespace(get_rel_namespace(rte->relid)))
- continue;
+ if (isTempNamespace(get_rel_namespace(rte->relid)))
+ continue;
- goto fail;
- }
+ goto fail;
}
return;
@@ -511,7 +509,7 @@ InitPlan(QueryDesc *queryDesc, bool explainOnly)
* rangetable here --- subplan RTEs will be checked during
* ExecInitSubPlan().
*/
- ExecCheckRTPerms(parseTree->rtable, operation);
+ ExecCheckRTPerms(parseTree->rtable);
/*
* get information from query descriptor