diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2000-09-29 18:21:41 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2000-09-29 18:21:41 +0000 |
commit | 3a94e789f5c9537d804210be3cb26f7fb08e3b9e (patch) | |
tree | f1eac12405e3c0ded881d7dd7e59cec35b30c335 /src/backend/rewrite/locks.c | |
parent | 6f64c2e54a0b14154a335249f4dca91a39c61c50 (diff) | |
download | postgresql-3a94e789f5c9537d804210be3cb26f7fb08e3b9e.tar.gz postgresql-3a94e789f5c9537d804210be3cb26f7fb08e3b9e.zip |
Subselects in FROM clause, per ISO syntax: FROM (SELECT ...) [AS] alias.
(Don't forget that an alias is required.) Views reimplemented as expanding
to subselect-in-FROM. Grouping, aggregates, DISTINCT in views actually
work now (he says optimistically). No UNION support in subselects/views
yet, but I have some ideas about that. Rule-related permissions checking
moved out of rewriter and into executor.
INITDB REQUIRED!
Diffstat (limited to 'src/backend/rewrite/locks.c')
-rw-r--r-- | src/backend/rewrite/locks.c | 268 |
1 files changed, 0 insertions, 268 deletions
diff --git a/src/backend/rewrite/locks.c b/src/backend/rewrite/locks.c deleted file mode 100644 index 78fdad8960a..00000000000 --- a/src/backend/rewrite/locks.c +++ /dev/null @@ -1,268 +0,0 @@ -/*------------------------------------------------------------------------- - * - * locks.c - * - * Portions Copyright (c) 1996-2000, PostgreSQL, Inc - * Portions Copyright (c) 1994, Regents of the University of California - * - * - * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/rewrite/Attic/locks.c,v 1.32 2000/09/12 21:07:02 tgl Exp $ - * - *------------------------------------------------------------------------- - */ -#include "postgres.h" - -#include "access/heapam.h" -#include "catalog/pg_shadow.h" -#include "optimizer/clauses.h" -#include "rewrite/locks.h" -#include "parser/parsetree.h" -#include "utils/acl.h" -#include "utils/syscache.h" - - -/* - * thisLockWasTriggered - * - * walk the tree, if there we find a varnode, - * we check the varattno against the attnum - * if we find at least one such match, we return true - * otherwise, we return false - * - * XXX this should be unified with attribute_used() - */ - -typedef struct -{ - int varno; - int attnum; - int sublevels_up; -} thisLockWasTriggered_context; - -static bool -thisLockWasTriggered_walker(Node *node, - thisLockWasTriggered_context *context) -{ - if (node == NULL) - return false; - if (IsA(node, Var)) - { - Var *var = (Var *) node; - - if (var->varlevelsup == context->sublevels_up && - var->varno == context->varno && - (var->varattno == context->attnum || context->attnum == -1)) - return true; - return false; - } - if (IsA(node, Query)) - { - /* Recurse into subselects */ - bool result; - - context->sublevels_up++; - result = query_tree_walker((Query *) node, thisLockWasTriggered_walker, - (void *) context); - context->sublevels_up--; - return result; - } - return expression_tree_walker(node, thisLockWasTriggered_walker, - (void *) context); -} - -static bool -thisLockWasTriggered(int varno, - int attnum, - Query *parsetree) -{ - thisLockWasTriggered_context context; - - context.varno = varno; - context.attnum = attnum; - context.sublevels_up = 0; - - return thisLockWasTriggered_walker((Node *) parsetree, &context); -} - -/* - * matchLocks - - * match the list of locks and returns the matching rules - */ -List * -matchLocks(CmdType event, - RuleLock *rulelocks, - int varno, - Query *parsetree) -{ - List *real_locks = NIL; - int nlocks; - int i; - - Assert(rulelocks != NULL); /* we get called iff there is some lock */ - Assert(parsetree != NULL); - - if (parsetree->commandType != CMD_SELECT) - { - if (parsetree->resultRelation != varno) - return NULL; - } - - nlocks = rulelocks->numLocks; - - for (i = 0; i < nlocks; i++) - { - RewriteRule *oneLock = rulelocks->rules[i]; - - if (oneLock->event == event) - { - if (parsetree->commandType != CMD_SELECT || - thisLockWasTriggered(varno, - oneLock->attrno, - parsetree)) - real_locks = lappend(real_locks, oneLock); - } - } - - checkLockPerms(real_locks, parsetree, varno); - - return real_locks; -} - - -/* - * Check the access permissions of tables that are referred to by a rule. - * We want to check the access permissions using the userid of the rule's - * owner, *not* of the current user (the one accessing the rule). So, we - * do the permission check here and set skipAcl = TRUE in each of the rule's - * RTEs, to prevent the executor from running another check with the current - * user's ID. - * - * XXX This routine is called before the rule's query tree has been copied - * out of the relcache entry where it is kept. Therefore, when we set - * skipAcl = TRUE, we are destructively modifying the relcache entry for - * the event relation! This seems fairly harmless because the relcache - * querytree is only used as a source for the rewriter, but it's a tad - * unclean anyway. - * - * Note that we must check permissions every time, even if skipAcl was - * already set TRUE by a prior call. This ensures that we enforce the - * current permission settings for each referenced table, even if they - * have changed since the relcache entry was loaded. - */ - -typedef struct -{ - Oid evowner; -} checkLockPerms_context; - -static bool -checkLockPerms_walker(Node *node, - checkLockPerms_context *context) -{ - if (node == NULL) - return false; - if (IsA(node, Query)) - { - Query *qry = (Query *) node; - int rtablength = length(qry->rtable); - int i; - - /* Check all the RTEs in this query node, except OLD and NEW */ - for (i = 1; i <= rtablength; i++) - { - RangeTblEntry *rte = rt_fetch(i, qry->rtable); - int32 reqperm; - int32 aclcheck_res; - - if (strcmp(rte->eref->relname, "*NEW*") == 0) - continue; - if (strcmp(rte->eref->relname, "*OLD*") == 0) - continue; - - if (i == qry->resultRelation) - switch (qry->commandType) - { - case CMD_INSERT: - reqperm = ACL_AP; - break; - default: - reqperm = ACL_WR; - break; - } - else - reqperm = ACL_RD; - - aclcheck_res = pg_aclcheck(rte->relname, - context->evowner, - reqperm); - if (aclcheck_res != ACLCHECK_OK) - elog(ERROR, "%s: %s", - rte->relname, - aclcheck_error_strings[aclcheck_res]); - - /* - * Mark RTE to prevent executor from checking again with the - * current user's ID... - */ - rte->skipAcl = true; - } - - /* If there are sublinks, search for them and check their RTEs */ - if (qry->hasSubLinks) - return query_tree_walker(qry, checkLockPerms_walker, - (void *) context); - return false; - } - return expression_tree_walker(node, checkLockPerms_walker, - (void *) context); -} - -void -checkLockPerms(List *locks, Query *parsetree, int rt_index) -{ - RangeTblEntry *rte; - Relation ev_rel; - HeapTuple usertup; - Form_pg_shadow userform; - checkLockPerms_context context; - List *l; - - if (locks == NIL) - return; /* nothing to check */ - - /* - * Get the userid of the rule's event relation owner - */ - rte = rt_fetch(rt_index, parsetree->rtable); - ev_rel = heap_openr(rte->relname, AccessShareLock); - usertup = SearchSysCacheTuple(SHADOWSYSID, - ObjectIdGetDatum(ev_rel->rd_rel->relowner), - 0, 0, 0); - if (!HeapTupleIsValid(usertup)) - elog(ERROR, "cache lookup for userid %d failed", - ev_rel->rd_rel->relowner); - userform = (Form_pg_shadow) GETSTRUCT(usertup); - context.evowner = userform->usesysid; - heap_close(ev_rel, AccessShareLock); - - /* - * Check all the locks that should get fired on this query - */ - foreach(l, locks) - { - RewriteRule *onelock = (RewriteRule *) lfirst(l); - List *action; - - /* - * In each lock check every action. We must scan the action - * recursively in case there are any sub-queries within it. - */ - foreach(action, onelock->actions) - { - Query *query = (Query *) lfirst(action); - - checkLockPerms_walker((Node *) query, &context); - } - } -} |