diff options
Diffstat (limited to 'src/backend/rewrite/rewriteHandler.c')
-rw-r--r-- | src/backend/rewrite/rewriteHandler.c | 1066 |
1 files changed, 559 insertions, 507 deletions
diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c index 093451655d0..980956a4807 100644 --- a/src/backend/rewrite/rewriteHandler.c +++ b/src/backend/rewrite/rewriteHandler.c @@ -6,7 +6,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.3 1997/08/12 22:53:41 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.4 1997/09/07 04:48:07 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -15,13 +15,13 @@ #include "utils/palloc.h" #include "utils/elog.h" #include "utils/rel.h" -#include "nodes/pg_list.h" +#include "nodes/pg_list.h" #include "nodes/primnodes.h" -#include "parser/parsetree.h" /* for parsetree manipulation */ +#include "parser/parsetree.h" /* for parsetree manipulation */ #include "nodes/parsenodes.h" -#include "rewrite/rewriteSupport.h" +#include "rewrite/rewriteSupport.h" #include "rewrite/rewriteHandler.h" #include "rewrite/rewriteManip.h" #include "rewrite/locks.h" @@ -29,529 +29,580 @@ #include "commands/creatinh.h" #include "access/heapam.h" -static void ApplyRetrieveRule(Query *parsetree, RewriteRule *rule, - int rt_index, int relation_level, int *modified); -static List *fireRules(Query *parsetree, int rt_index, CmdType event, - bool *instead_flag, List *locks, List **qual_products); -static List *deepRewriteQuery(Query *parsetree); +static void +ApplyRetrieveRule(Query * parsetree, RewriteRule * rule, + int rt_index, int relation_level, int *modified); +static List * +fireRules(Query * parsetree, int rt_index, CmdType event, + bool * instead_flag, List * locks, List ** qual_products); +static List *deepRewriteQuery(Query * parsetree); /* * gatherRewriteMeta - - * Gather meta information about parsetree, and rule. Fix rule body - * and qualifier so that they can be mixed with the parsetree and - * maintain semantic validity + * Gather meta information about parsetree, and rule. Fix rule body + * and qualifier so that they can be mixed with the parsetree and + * maintain semantic validity */ static RewriteInfo * -gatherRewriteMeta(Query *parsetree, - Query *rule_action, - Node *rule_qual, - int rt_index, - CmdType event, - bool *instead_flag) +gatherRewriteMeta(Query * parsetree, + Query * rule_action, + Node * rule_qual, + int rt_index, + CmdType event, + bool * instead_flag) { - RewriteInfo *info; - int rt_length; - int result_reln; - - info = (RewriteInfo *) palloc(sizeof(RewriteInfo)); - info->rt_index = rt_index; - info->event = event; - info->instead_flag = *instead_flag; - info->rule_action = (Query*)copyObject(rule_action); - info->rule_qual = (Node*)copyObject(rule_qual); - if (info->rule_action == NULL) info->nothing = TRUE; - else { - info->nothing = FALSE; - info->action = info->rule_action->commandType; - info->current_varno = rt_index; - info->rt = parsetree->rtable; - rt_length = length(info->rt); - info->rt = append(info->rt, info->rule_action->rtable); - - info->new_varno = PRS2_NEW_VARNO + rt_length; - OffsetVarNodes(info->rule_action->qual, rt_length); - OffsetVarNodes((Node*)info->rule_action->targetList, rt_length); - OffsetVarNodes(info->rule_qual, rt_length); - ChangeVarNodes((Node*)info->rule_action->qual, - PRS2_CURRENT_VARNO+rt_length, rt_index); - ChangeVarNodes((Node*)info->rule_action->targetList, - PRS2_CURRENT_VARNO+rt_length, rt_index); - ChangeVarNodes(info->rule_qual, - PRS2_CURRENT_VARNO+rt_length, rt_index); - - /* - * bug here about replace CURRENT -- sort of - * replace current is deprecated now so this code shouldn't really - * need to be so clutzy but..... - */ - if (info->action != CMD_SELECT) { /* i.e update XXXXX */ - int new_result_reln = 0; - result_reln = info->rule_action->resultRelation; - switch (result_reln) { - case PRS2_CURRENT_VARNO: new_result_reln = rt_index; - break; - case PRS2_NEW_VARNO: /* XXX */ - default: - new_result_reln = result_reln + rt_length; - break; - } - info->rule_action->resultRelation = new_result_reln; - } - } - return info; + RewriteInfo *info; + int rt_length; + int result_reln; + + info = (RewriteInfo *) palloc(sizeof(RewriteInfo)); + info->rt_index = rt_index; + info->event = event; + info->instead_flag = *instead_flag; + info->rule_action = (Query *) copyObject(rule_action); + info->rule_qual = (Node *) copyObject(rule_qual); + if (info->rule_action == NULL) + info->nothing = TRUE; + else + { + info->nothing = FALSE; + info->action = info->rule_action->commandType; + info->current_varno = rt_index; + info->rt = parsetree->rtable; + rt_length = length(info->rt); + info->rt = append(info->rt, info->rule_action->rtable); + + info->new_varno = PRS2_NEW_VARNO + rt_length; + OffsetVarNodes(info->rule_action->qual, rt_length); + OffsetVarNodes((Node *) info->rule_action->targetList, rt_length); + OffsetVarNodes(info->rule_qual, rt_length); + ChangeVarNodes((Node *) info->rule_action->qual, + PRS2_CURRENT_VARNO + rt_length, rt_index); + ChangeVarNodes((Node *) info->rule_action->targetList, + PRS2_CURRENT_VARNO + rt_length, rt_index); + ChangeVarNodes(info->rule_qual, + PRS2_CURRENT_VARNO + rt_length, rt_index); + + /* + * bug here about replace CURRENT -- sort of replace current is + * deprecated now so this code shouldn't really need to be so + * clutzy but..... + */ + if (info->action != CMD_SELECT) + { /* i.e update XXXXX */ + int new_result_reln = 0; + + result_reln = info->rule_action->resultRelation; + switch (result_reln) + { + case PRS2_CURRENT_VARNO: + new_result_reln = rt_index; + break; + case PRS2_NEW_VARNO: /* XXX */ + default: + new_result_reln = result_reln + rt_length; + break; + } + info->rule_action->resultRelation = new_result_reln; + } + } + return info; } -static List * -OptimizeRIRRules(List *locks) +static List * +OptimizeRIRRules(List * locks) { - List *attr_level = NIL, *i; - List *relation_level = NIL; - - foreach (i, locks) { - RewriteRule *rule_lock = lfirst(i); - - if (rule_lock->attrno == -1) - relation_level = lappend(relation_level, rule_lock); - else - attr_level = lappend(attr_level, rule_lock); - } - return nconc(relation_level, attr_level); + List *attr_level = NIL, + *i; + List *relation_level = NIL; + + foreach(i, locks) + { + RewriteRule *rule_lock = lfirst(i); + + if (rule_lock->attrno == -1) + relation_level = lappend(relation_level, rule_lock); + else + attr_level = lappend(attr_level, rule_lock); + } + return nconc(relation_level, attr_level); } /* * idea is to put instead rules before regular rules so that * excess semantically queasy queries aren't processed */ -static List * -orderRules(List *locks) +static List * +orderRules(List * locks) { - List *regular = NIL, *i; - List *instead_rules = NIL; - - foreach (i, locks) { - RewriteRule *rule_lock = (RewriteRule *)lfirst(i); - - if (rule_lock->isInstead) - instead_rules = lappend(instead_rules, rule_lock); - else - regular = lappend(regular, rule_lock); - } - return nconc(regular, instead_rules); + List *regular = NIL, + *i; + List *instead_rules = NIL; + + foreach(i, locks) + { + RewriteRule *rule_lock = (RewriteRule *) lfirst(i); + + if (rule_lock->isInstead) + instead_rules = lappend(instead_rules, rule_lock); + else + regular = lappend(regular, rule_lock); + } + return nconc(regular, instead_rules); } static int -AllRetrieve(List *actions) +AllRetrieve(List * actions) { - List *n; - - foreach(n, actions) { - Query *pt = lfirst(n); - - /* - * in the old postgres code, we check whether command_type is - * a consp of '('*'.commandType). but we've never supported transitive - * closures. Hence removed - ay 10/94. - */ - if (pt->commandType != CMD_SELECT) - return false; - } - return true; + List *n; + + foreach(n, actions) + { + Query *pt = lfirst(n); + + /* + * in the old postgres code, we check whether command_type is a + * consp of '('*'.commandType). but we've never supported + * transitive closures. Hence removed - ay 10/94. + */ + if (pt->commandType != CMD_SELECT) + return false; + } + return true; } -static List * -FireRetrieveRulesAtQuery(Query *parsetree, - int rt_index, - Relation relation, - bool *instead_flag, - int rule_flag) +static List * +FireRetrieveRulesAtQuery(Query * parsetree, + int rt_index, + Relation relation, + bool * instead_flag, + int rule_flag) { - List *i, *locks; - RuleLock *rt_entry_locks = NULL; - List *work = NIL; + List *i, + *locks; + RuleLock *rt_entry_locks = NULL; + List *work = NIL; - if ((rt_entry_locks = relation->rd_rules) == NULL) - return NIL; - - locks = matchLocks(CMD_SELECT, rt_entry_locks, rt_index, parsetree); - - /* find all retrieve instead */ - foreach (i, locks) { - RewriteRule *rule_lock = (RewriteRule *)lfirst(i); - - if (!rule_lock->isInstead) - continue; - work = lappend(work, rule_lock); - } - if (work != NIL) { - work = OptimizeRIRRules(locks); - foreach (i, work) { - RewriteRule *rule_lock = lfirst(i); - int relation_level; - int modified = FALSE; - - relation_level = (rule_lock->attrno == -1); - if (rule_lock->actions == NIL) { - *instead_flag = TRUE; + if ((rt_entry_locks = relation->rd_rules) == NULL) return NIL; - } - if (!rule_flag && - length(rule_lock->actions) >= 2 && - AllRetrieve(rule_lock->actions)) { - *instead_flag = TRUE; - return rule_lock->actions; - } - ApplyRetrieveRule(parsetree, rule_lock, rt_index, relation_level, - &modified); - if (modified) { - *instead_flag = TRUE; - FixResdomTypes(parsetree->targetList); - return lcons(parsetree,NIL); - } + + locks = matchLocks(CMD_SELECT, rt_entry_locks, rt_index, parsetree); + + /* find all retrieve instead */ + foreach(i, locks) + { + RewriteRule *rule_lock = (RewriteRule *) lfirst(i); + + if (!rule_lock->isInstead) + continue; + work = lappend(work, rule_lock); + } + if (work != NIL) + { + work = OptimizeRIRRules(locks); + foreach(i, work) + { + RewriteRule *rule_lock = lfirst(i); + int relation_level; + int modified = FALSE; + + relation_level = (rule_lock->attrno == -1); + if (rule_lock->actions == NIL) + { + *instead_flag = TRUE; + return NIL; + } + if (!rule_flag && + length(rule_lock->actions) >= 2 && + AllRetrieve(rule_lock->actions)) + { + *instead_flag = TRUE; + return rule_lock->actions; + } + ApplyRetrieveRule(parsetree, rule_lock, rt_index, relation_level, + &modified); + if (modified) + { + *instead_flag = TRUE; + FixResdomTypes(parsetree->targetList); + return lcons(parsetree, NIL); + } + } } - } - return NIL; -} + return NIL; +} /* Idea is like this: * * retrieve-instead-retrieve rules have different semantics than update nodes - * Separate RIR rules from others. Pass others to FireRules. + * Separate RIR rules from others. Pass others to FireRules. * Order RIR rules and process. * * side effect: parsetree's rtable field might be changed */ static void -ApplyRetrieveRule(Query *parsetree, - RewriteRule *rule, - int rt_index, - int relation_level, - int *modified) +ApplyRetrieveRule(Query * parsetree, + RewriteRule * rule, + int rt_index, + int relation_level, + int *modified) { - Query *rule_action = NULL; - Node *rule_qual; - List *rtable, *rt; - int nothing, rt_length; - int badsql= FALSE; - - rule_qual = rule->qual; - if (rule->actions) { - if (length(rule->actions) > 1) /* ??? because we don't handle rules - with more than one action? -ay */ - return; - rule_action = copyObject(lfirst(rule->actions)); - nothing = FALSE; - } else { - nothing = TRUE; - } - - rtable = copyObject(parsetree->rtable); - foreach (rt, rtable) { - RangeTblEntry *rte = lfirst(rt); - /* - * this is to prevent add_missing_vars_to_base_rels() from - * adding a bogus entry to the new target list. - */ - rte->inFromCl = false; - } - rt_length = length(rtable); - rtable = nconc(rtable, copyObject(rule_action->rtable)); - parsetree->rtable = rtable; - - rule_action->rtable = rtable; - OffsetVarNodes(rule_action->qual, rt_length); - OffsetVarNodes((Node*)rule_action->targetList, rt_length); - OffsetVarNodes(rule_qual, rt_length); - ChangeVarNodes(rule_action->qual, - PRS2_CURRENT_VARNO+rt_length, rt_index); - ChangeVarNodes((Node*)rule_action->targetList, - PRS2_CURRENT_VARNO+rt_length, rt_index); - ChangeVarNodes(rule_qual, PRS2_CURRENT_VARNO+rt_length, rt_index); - if (relation_level) { - HandleViewRule(parsetree, rtable, rule_action->targetList, rt_index, - modified); - } else { - HandleRIRAttributeRule(parsetree, rtable, rule_action->targetList, - rt_index, rule->attrno, modified, &badsql); - } - if (*modified && !badsql) - AddQual(parsetree, rule_action->qual); + Query *rule_action = NULL; + Node *rule_qual; + List *rtable, + *rt; + int nothing, + rt_length; + int badsql = FALSE; + + rule_qual = rule->qual; + if (rule->actions) + { + if (length(rule->actions) > 1) /* ??? because we don't handle + * rules with more than one + * action? -ay */ + return; + rule_action = copyObject(lfirst(rule->actions)); + nothing = FALSE; + } + else + { + nothing = TRUE; + } + + rtable = copyObject(parsetree->rtable); + foreach(rt, rtable) + { + RangeTblEntry *rte = lfirst(rt); + + /* + * this is to prevent add_missing_vars_to_base_rels() from adding + * a bogus entry to the new target list. + */ + rte->inFromCl = false; + } + rt_length = length(rtable); + rtable = nconc(rtable, copyObject(rule_action->rtable)); + parsetree->rtable = rtable; + + rule_action->rtable = rtable; + OffsetVarNodes(rule_action->qual, rt_length); + OffsetVarNodes((Node *) rule_action->targetList, rt_length); + OffsetVarNodes(rule_qual, rt_length); + ChangeVarNodes(rule_action->qual, + PRS2_CURRENT_VARNO + rt_length, rt_index); + ChangeVarNodes((Node *) rule_action->targetList, + PRS2_CURRENT_VARNO + rt_length, rt_index); + ChangeVarNodes(rule_qual, PRS2_CURRENT_VARNO + rt_length, rt_index); + if (relation_level) + { + HandleViewRule(parsetree, rtable, rule_action->targetList, rt_index, + modified); + } + else + { + HandleRIRAttributeRule(parsetree, rtable, rule_action->targetList, + rt_index, rule->attrno, modified, &badsql); + } + if (*modified && !badsql) + AddQual(parsetree, rule_action->qual); } -static List * -ProcessRetrieveQuery(Query *parsetree, - List *rtable, - bool *instead_flag, - bool rule) +static List * +ProcessRetrieveQuery(Query * parsetree, + List * rtable, + bool * instead_flag, + bool rule) { - List *rt; - List *product_queries = NIL; - int rt_index = 0; - - foreach (rt, rtable) { - RangeTblEntry *rt_entry = lfirst(rt); - Relation rt_entry_relation = NULL; - List *result = NIL; - - rt_index++; - rt_entry_relation = heap_openr(rt_entry->relname); - - if (rt_entry_relation->rd_rules != NULL) { - result = - FireRetrieveRulesAtQuery(parsetree, - rt_index, - rt_entry_relation, - instead_flag, - rule); + List *rt; + List *product_queries = NIL; + int rt_index = 0; + + foreach(rt, rtable) + { + RangeTblEntry *rt_entry = lfirst(rt); + Relation rt_entry_relation = NULL; + List *result = NIL; + + rt_index++; + rt_entry_relation = heap_openr(rt_entry->relname); + + if (rt_entry_relation->rd_rules != NULL) + { + result = + FireRetrieveRulesAtQuery(parsetree, + rt_index, + rt_entry_relation, + instead_flag, + rule); + } + heap_close(rt_entry_relation); + if (*instead_flag) + return result; } - heap_close(rt_entry_relation); - if (*instead_flag) - return result; - } - if (rule) - return NIL; + if (rule) + return NIL; - foreach (rt, rtable) { - RangeTblEntry *rt_entry = lfirst(rt); - Relation rt_entry_relation = NULL; - RuleLock *rt_entry_locks = NULL; - List *result = NIL; - List *locks = NIL; - List *dummy_products; - - rt_index++; - rt_entry_relation = heap_openr(rt_entry->relname); - rt_entry_locks = rt_entry_relation->rd_rules; - heap_close(rt_entry_relation); - - if (rt_entry_locks) { - locks = - matchLocks(CMD_SELECT, rt_entry_locks, rt_index, parsetree); + foreach(rt, rtable) + { + RangeTblEntry *rt_entry = lfirst(rt); + Relation rt_entry_relation = NULL; + RuleLock *rt_entry_locks = NULL; + List *result = NIL; + List *locks = NIL; + List *dummy_products; + + rt_index++; + rt_entry_relation = heap_openr(rt_entry->relname); + rt_entry_locks = rt_entry_relation->rd_rules; + heap_close(rt_entry_relation); + + if (rt_entry_locks) + { + locks = + matchLocks(CMD_SELECT, rt_entry_locks, rt_index, parsetree); + } + if (locks != NIL) + { + result = fireRules(parsetree, rt_index, CMD_SELECT, + instead_flag, locks, &dummy_products); + if (*instead_flag) + return lappend(NIL, result); + if (result != NIL) + product_queries = nconc(product_queries, result); + } } - if (locks != NIL) { - result = fireRules(parsetree, rt_index, CMD_SELECT, - instead_flag, locks, &dummy_products); - if (*instead_flag) - return lappend(NIL, result); - if (result != NIL) - product_queries = nconc(product_queries, result); - } - } - return product_queries; + return product_queries; } -static Query * -CopyAndAddQual(Query *parsetree, - List *actions, - Node *rule_qual, - int rt_index, - CmdType event) +static Query * +CopyAndAddQual(Query * parsetree, + List * actions, + Node * rule_qual, + int rt_index, + CmdType event) { - Query *new_tree = (Query *) copyObject(parsetree); - Node *new_qual = NULL; - Query *rule_action = NULL; - - if (actions) - rule_action = lfirst(actions); - if (rule_qual != NULL) - new_qual = (Node *)copyObject(rule_qual); - if (rule_action != NULL) { - List *rtable; - int rt_length; - - rtable = new_tree->rtable; - rt_length = length(rtable); - rtable = append(rtable,listCopy(rule_action->rtable)); - new_tree->rtable = rtable; - OffsetVarNodes(new_qual, rt_length); - ChangeVarNodes(new_qual, PRS2_CURRENT_VARNO+rt_length, rt_index); - } - /* XXX -- where current doesn't work for instead nothing.... yet*/ - AddNotQual(new_tree, new_qual); - - return new_tree; + Query *new_tree = (Query *) copyObject(parsetree); + Node *new_qual = NULL; + Query *rule_action = NULL; + + if (actions) + rule_action = lfirst(actions); + if (rule_qual != NULL) + new_qual = (Node *) copyObject(rule_qual); + if (rule_action != NULL) + { + List *rtable; + int rt_length; + + rtable = new_tree->rtable; + rt_length = length(rtable); + rtable = append(rtable, listCopy(rule_action->rtable)); + new_tree->rtable = rtable; + OffsetVarNodes(new_qual, rt_length); + ChangeVarNodes(new_qual, PRS2_CURRENT_VARNO + rt_length, rt_index); + } + /* XXX -- where current doesn't work for instead nothing.... yet */ + AddNotQual(new_tree, new_qual); + + return new_tree; } /* - * fireRules - - * Iterate through rule locks applying rules. After an instead rule - * rule has been applied, return just new parsetree and let RewriteQuery - * start the process all over again. The locks are reordered to maintain - * sensible semantics. remember: reality is for dead birds -- glass + * fireRules - + * Iterate through rule locks applying rules. After an instead rule + * rule has been applied, return just new parsetree and let RewriteQuery + * start the process all over again. The locks are reordered to maintain + * sensible semantics. remember: reality is for dead birds -- glass * */ -static List * -fireRules(Query *parsetree, - int rt_index, - CmdType event, - bool *instead_flag, - List *locks, - List **qual_products) +static List * +fireRules(Query * parsetree, + int rt_index, + CmdType event, + bool * instead_flag, + List * locks, + List ** qual_products) { - RewriteInfo *info; - List *results = NIL; - List *i; - - /* choose rule to fire from list of rules */ - if (locks == NIL) { - ProcessRetrieveQuery(parsetree, - parsetree->rtable, - instead_flag, TRUE); - if (*instead_flag) - return lappend(NIL, parsetree); - else - return NIL; - } - - locks = orderRules(locks); /* instead rules first */ - foreach (i, locks) { - RewriteRule *rule_lock = (RewriteRule *)lfirst(i); - Node *qual, *event_qual; - List *actions; - List *r; - bool orig_instead_flag = *instead_flag; - - /* multiple rule action time */ - *instead_flag = rule_lock->isInstead; - event_qual = rule_lock->qual; - actions = rule_lock->actions; - if (event_qual != NULL && *instead_flag) - *qual_products = - lappend(*qual_products, - CopyAndAddQual(parsetree, actions, event_qual, - rt_index, event)); - foreach (r, actions) { - Query *rule_action = lfirst(r); - Node *rule_qual = copyObject(event_qual); - - /*-------------------------------------------------- - * Step 1: - * Rewrite current.attribute or current to tuple variable - * this appears to be done in parser? - *-------------------------------------------------- - */ - info = gatherRewriteMeta(parsetree, rule_action, rule_qual, - rt_index,event,instead_flag); - - /* handle escapable cases, or those handled by other code */ - if (info->nothing) { + RewriteInfo *info; + List *results = NIL; + List *i; + + /* choose rule to fire from list of rules */ + if (locks == NIL) + { + ProcessRetrieveQuery(parsetree, + parsetree->rtable, + instead_flag, TRUE); if (*instead_flag) - return NIL; + return lappend(NIL, parsetree); else - continue; - } - - if (info->action == info->event && - info->event == CMD_SELECT) - continue; - - /* - * Event Qualification forces copying of parsetree --- XXX - * and splitting into two queries one w/rule_qual, one - * w/NOT rule_qual. Also add user query qual onto rule action - */ - qual = parsetree->qual; - AddQual(info->rule_action, qual); - - if (info->rule_qual != NULL) - AddQual(info->rule_action, info->rule_qual); - - /*-------------------------------------------------- - * Step 2: - * Rewrite new.attribute w/ right hand side of target-list - * entry for appropriate field name in insert/update - *-------------------------------------------------- - */ - if ((info->event == CMD_INSERT) || (info->event == CMD_UPDATE)) { - FixNew(info, parsetree); - } - - /*-------------------------------------------------- - * Step 3: - * rewriting due to retrieve rules - *-------------------------------------------------- - */ - info->rule_action->rtable = info->rt; - ProcessRetrieveQuery(info->rule_action, info->rt, - &orig_instead_flag, TRUE); - - /*-------------------------------------------------- - * Step 4 - * Simplify? hey, no algorithm for simplification... let - * the planner do it. - *-------------------------------------------------- - */ - results = lappend(results, info->rule_action); - - pfree(info); + return NIL; } - if (*instead_flag) break; - } - return results; + + locks = orderRules(locks); /* instead rules first */ + foreach(i, locks) + { + RewriteRule *rule_lock = (RewriteRule *) lfirst(i); + Node *qual, + *event_qual; + List *actions; + List *r; + bool orig_instead_flag = *instead_flag; + + /* multiple rule action time */ + *instead_flag = rule_lock->isInstead; + event_qual = rule_lock->qual; + actions = rule_lock->actions; + if (event_qual != NULL && *instead_flag) + *qual_products = + lappend(*qual_products, + CopyAndAddQual(parsetree, actions, event_qual, + rt_index, event)); + foreach(r, actions) + { + Query *rule_action = lfirst(r); + Node *rule_qual = copyObject(event_qual); + + /*-------------------------------------------------- + * Step 1: + * Rewrite current.attribute or current to tuple variable + * this appears to be done in parser? + *-------------------------------------------------- + */ + info = gatherRewriteMeta(parsetree, rule_action, rule_qual, + rt_index, event, instead_flag); + + /* handle escapable cases, or those handled by other code */ + if (info->nothing) + { + if (*instead_flag) + return NIL; + else + continue; + } + + if (info->action == info->event && + info->event == CMD_SELECT) + continue; + + /* + * Event Qualification forces copying of parsetree --- XXX and + * splitting into two queries one w/rule_qual, one w/NOT + * rule_qual. Also add user query qual onto rule action + */ + qual = parsetree->qual; + AddQual(info->rule_action, qual); + + if (info->rule_qual != NULL) + AddQual(info->rule_action, info->rule_qual); + + /*-------------------------------------------------- + * Step 2: + * Rewrite new.attribute w/ right hand side of target-list + * entry for appropriate field name in insert/update + *-------------------------------------------------- + */ + if ((info->event == CMD_INSERT) || (info->event == CMD_UPDATE)) + { + FixNew(info, parsetree); + } + + /*-------------------------------------------------- + * Step 3: + * rewriting due to retrieve rules + *-------------------------------------------------- + */ + info->rule_action->rtable = info->rt; + ProcessRetrieveQuery(info->rule_action, info->rt, + &orig_instead_flag, TRUE); + + /*-------------------------------------------------- + * Step 4 + * Simplify? hey, no algorithm for simplification... let + * the planner do it. + *-------------------------------------------------- + */ + results = lappend(results, info->rule_action); + + pfree(info); + } + if (*instead_flag) + break; + } + return results; } -static List * -RewriteQuery(Query *parsetree, bool *instead_flag, List **qual_products) +static List * +RewriteQuery(Query * parsetree, bool * instead_flag, List ** qual_products) { - CmdType event; - List *product_queries = NIL; - int result_relation = 0; - - Assert(parsetree != NULL); - - event = parsetree->commandType; - - if (event == CMD_UTILITY) - return NIL; + CmdType event; + List *product_queries = NIL; + int result_relation = 0; - /* - * only for a delete may the targetlist be NULL - */ - if (event != CMD_DELETE) { - Assert(parsetree->targetList != NULL); - } - - result_relation = parsetree->resultRelation; + Assert(parsetree != NULL); + + event = parsetree->commandType; + + if (event == CMD_UTILITY) + return NIL; - if (event != CMD_SELECT) { /* - * the statement is an update, insert or delete + * only for a delete may the targetlist be NULL */ - RangeTblEntry *rt_entry; - Relation rt_entry_relation = NULL; - RuleLock *rt_entry_locks = NULL; - - rt_entry = rt_fetch(result_relation, parsetree->rtable); - rt_entry_relation = heap_openr(rt_entry->relname); - rt_entry_locks = rt_entry_relation->rd_rules; - heap_close(rt_entry_relation); - - if (rt_entry_locks != NULL) { - List *locks = - matchLocks(event, rt_entry_locks, result_relation, parsetree); - - product_queries = - fireRules(parsetree, - result_relation, - event, - instead_flag, - locks, - qual_products); + if (event != CMD_DELETE) + { + Assert(parsetree->targetList != NULL); + } + + result_relation = parsetree->resultRelation; + + if (event != CMD_SELECT) + { + + /* + * the statement is an update, insert or delete + */ + RangeTblEntry *rt_entry; + Relation rt_entry_relation = NULL; + RuleLock *rt_entry_locks = NULL; + + rt_entry = rt_fetch(result_relation, parsetree->rtable); + rt_entry_relation = heap_openr(rt_entry->relname); + rt_entry_locks = rt_entry_relation->rd_rules; + heap_close(rt_entry_relation); + + if (rt_entry_locks != NULL) + { + List *locks = + matchLocks(event, rt_entry_locks, result_relation, parsetree); + + product_queries = + fireRules(parsetree, + result_relation, + event, + instead_flag, + locks, + qual_products); + } + return product_queries; + } + else + { + + /* + * the statement is a select + */ + Query *other; + + other = copyObject(parsetree); /* ApplyRetrieveRule changes the + * range table */ + return + ProcessRetrieveQuery(other, parsetree->rtable, + instead_flag, FALSE); } - return product_queries; - }else { - /* - * the statement is a select - */ - Query *other; - - other = copyObject(parsetree); /* ApplyRetrieveRule changes the - range table */ - return - ProcessRetrieveQuery(other, parsetree->rtable, - instead_flag, FALSE); - } } /* @@ -559,61 +610,62 @@ RewriteQuery(Query *parsetree, bool *instead_flag, List **qual_products) * can be rewritten. Detecting cycles is left for the reader as an excercise. */ #ifndef REWRITE_INVOKE_MAX -#define REWRITE_INVOKE_MAX 10 +#define REWRITE_INVOKE_MAX 10 #endif -static int numQueryRewriteInvoked = 0; +static int numQueryRewriteInvoked = 0; /* * QueryRewrite - - * rewrite one query via QueryRewrite system, possibly returning 0, or many - * queries - */ -List * -QueryRewrite(Query *parsetree) + * rewrite one query via QueryRewrite system, possibly returning 0, or many + * queries + */ +List * +QueryRewrite(Query * parsetree) { - numQueryRewriteInvoked = 0; + numQueryRewriteInvoked = 0; - /* - * take a deep breath and apply all the rewrite rules - ay - */ - return deepRewriteQuery(parsetree); + /* + * take a deep breath and apply all the rewrite rules - ay + */ + return deepRewriteQuery(parsetree); } /* * deepRewriteQuery - - * rewrites the query and apply the rules again on the queries rewritten + * rewrites the query and apply the rules again on the queries rewritten */ -static List * -deepRewriteQuery(Query *parsetree) +static List * +deepRewriteQuery(Query * parsetree) { - List *n; - List *rewritten = NIL; - List *result = NIL; - bool instead; - List *qual_products = NIL; - - if (++numQueryRewriteInvoked > REWRITE_INVOKE_MAX) { - elog(WARN, "query rewritten %d times, may contain cycles", - numQueryRewriteInvoked-1); - } - - instead = FALSE; - result = RewriteQuery(parsetree, &instead, &qual_products); - if (!instead) - rewritten = lcons(parsetree, NIL); - - foreach(n, result) { - Query *pt = lfirst(n); - List *newstuff = NIL; - - newstuff = deepRewriteQuery(pt); - if (newstuff != NIL) - rewritten = nconc(rewritten, newstuff); - } - if (qual_products != NIL) - rewritten = nconc(rewritten, qual_products); - - return rewritten; -} + List *n; + List *rewritten = NIL; + List *result = NIL; + bool instead; + List *qual_products = NIL; + + if (++numQueryRewriteInvoked > REWRITE_INVOKE_MAX) + { + elog(WARN, "query rewritten %d times, may contain cycles", + numQueryRewriteInvoked - 1); + } + + instead = FALSE; + result = RewriteQuery(parsetree, &instead, &qual_products); + if (!instead) + rewritten = lcons(parsetree, NIL); + foreach(n, result) + { + Query *pt = lfirst(n); + List *newstuff = NIL; + + newstuff = deepRewriteQuery(pt); + if (newstuff != NIL) + rewritten = nconc(rewritten, newstuff); + } + if (qual_products != NIL) + rewritten = nconc(rewritten, qual_products); + + return rewritten; +} |