diff options
Diffstat (limited to 'src/backend/executor/execMain.c')
-rw-r--r-- | src/backend/executor/execMain.c | 120 |
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 |