77 * Portions Copyright (c) 1994, Regents of the University of California
88 *
99 * IDENTIFICATION
10- * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.111 2002/10/14 22:14:35 tgl Exp $
10+ * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.112 2002/10/19 19:00:47 tgl Exp $
1111 *
1212 *-------------------------------------------------------------------------
1313 */
@@ -503,7 +503,7 @@ matchLocks(CmdType event,
503503int varno ,
504504Query * parsetree )
505505{
506- List * real_locks = NIL ;
506+ List * matching_locks = NIL ;
507507int nlocks ;
508508int i ;
509509
@@ -529,11 +529,11 @@ matchLocks(CmdType event,
529529rangeTableEntry_used ((Node * )parsetree ,varno ,0 ) :
530530attribute_used ((Node * )parsetree ,
531531varno ,oneLock -> attrno ,0 )))
532- real_locks = lappend (real_locks ,oneLock );
532+ matching_locks = lappend (matching_locks ,oneLock );
533533}
534534}
535535
536- return real_locks ;
536+ return matching_locks ;
537537}
538538
539539
@@ -841,36 +841,6 @@ fireRIRrules(Query *parsetree)
841841}
842842
843843
844- /*
845- * idea is to fire regular rules first, then qualified instead
846- * rules and unqualified instead rules last. Any lemming is counted for.
847- */
848- static List *
849- orderRules (List * locks )
850- {
851- List * regular = NIL ;
852- List * instead_rules = NIL ;
853- List * instead_qualified = NIL ;
854- List * i ;
855-
856- foreach (i ,locks )
857- {
858- RewriteRule * rule_lock = (RewriteRule * )lfirst (i );
859-
860- if (rule_lock -> isInstead )
861- {
862- if (rule_lock -> qual == NULL )
863- instead_rules = lappend (instead_rules ,rule_lock );
864- else
865- instead_qualified = lappend (instead_qualified ,rule_lock );
866- }
867- else
868- regular = lappend (regular ,rule_lock );
869- }
870- return nconc (nconc (regular ,instead_qualified ),instead_rules );
871- }
872-
873-
874844/*
875845 * Modify the given query by adding 'AND NOT rule_qual' to its qualification.
876846 * This is used to generate suitable "else clauses" for conditional INSTEAD
@@ -908,84 +878,89 @@ CopyAndAddQual(Query *parsetree,
908878}
909879
910880
911-
912881/*
913882 *fireRules -
914883 * Iterate through rule locks applying rules.
915- * All rules create their own parsetrees. Instead rules
916- * with rule qualification save the original parsetree
917- * and add their negated qualification to it. Real instead
918- * rules finally throw away the original parsetree.
919884 *
920- * remember: reality is for dead birds -- glass
885+ * Input arguments:
886+ *parsetree - original query
887+ *rt_index - RT index of result relation in original query
888+ *event - type of rule event
889+ *locks - list of rules to fire
890+ * Output arguments:
891+ **instead_flag - set TRUE if any unqualified INSTEAD rule is found
892+ *(must be initialized to FALSE)
893+ **qual_product - filled with modified original query if any qualified
894+ *INSTEAD rule is found (must be initialized to NULL)
895+ * Return value:
896+ *list of rule actions adjusted for use with this query
921897 *
898+ * Qualified INSTEAD rules generate their action with the qualification
899+ * condition added. They also generate a modified version of the original
900+ * query with the negated qualification added, so that it will run only for
901+ * rows that the qualified action doesn't act on. (If there are multiple
902+ * qualified INSTEAD rules, we AND all the negated quals onto a single
903+ * modified original query.) We won't execute the original, unmodified
904+ * query if we find either qualified or unqualified INSTEAD rules. If
905+ * we find both, the modified original query is discarded too.
922906 */
923907static List *
924908fireRules (Query * parsetree ,
925909int rt_index ,
926910CmdType event ,
927- bool * instead_flag ,
928911List * locks ,
929- List * * qual_products )
912+ bool * instead_flag ,
913+ Query * * qual_product )
930914{
931915List * results = NIL ;
932916List * i ;
933917
934- /* choose rule to fire from list of rules */
935- if (locks == NIL )
936- return NIL ;
937-
938- locks = orderRules (locks );/* real instead rules last */
939-
940918foreach (i ,locks )
941919{
942920RewriteRule * rule_lock = (RewriteRule * )lfirst (i );
943- Node * event_qual ;
944- List * actions ;
921+ Node * event_qual = rule_lock -> qual ;
922+ List * actions = rule_lock -> actions ;
945923QuerySource qsrc ;
946924List * r ;
947925
948- /* multiple rule action time */
949- * instead_flag = rule_lock -> isInstead ;
950- event_qual = rule_lock -> qual ;
951- actions = rule_lock -> actions ;
952-
953926/* Determine correct QuerySource value for actions */
954927if (rule_lock -> isInstead )
955928{
956929if (event_qual != NULL )
957930qsrc = QSRC_QUAL_INSTEAD_RULE ;
958931else
932+ {
959933qsrc = QSRC_INSTEAD_RULE ;
934+ * instead_flag = true;/* report unqualified INSTEAD */
935+ }
960936}
961937else
962938qsrc = QSRC_NON_INSTEAD_RULE ;
963939
964940if (qsrc == QSRC_QUAL_INSTEAD_RULE )
965941{
966- Query * qual_product ;
967-
968942/*
969- * If there areinstead rules with qualifications, the
943+ * If there areINSTEAD rules with qualifications, the
970944 * original query is still performed. But all the negated rule
971- * qualifications of theinstead rules are added so it does
945+ * qualifications of theINSTEAD rules are added so it does
972946 * its actions only in cases where the rule quals of all
973- *instead rules are false. Think of it as the default action
974- * in a case. We save this in *qual_products so
947+ *INSTEAD rules are false. Think of it as the default action
948+ * in a case. We save this in *qual_product so
975949 * deepRewriteQuery() can add it to the query list after we
976950 * mangled it up enough.
951+ *
952+ * If we have already found an unqualified INSTEAD rule,
953+ * then *qual_product won't be used, so don't bother building it.
977954 */
978- if (* qual_products == NIL )
979- qual_product = parsetree ;
980- else
981- qual_product = (Query * )lfirst (* qual_products );
982-
983- qual_product = CopyAndAddQual (qual_product ,
984- event_qual ,
985- rt_index ,
986- event );
987-
988- * qual_products = makeList1 (qual_product );
955+ if (!* instead_flag )
956+ {
957+ if (* qual_product == NULL )
958+ * qual_product = parsetree ;
959+ * qual_product = CopyAndAddQual (* qual_product ,
960+ event_qual ,
961+ rt_index ,
962+ event );
963+ }
989964}
990965
991966/* Now process the rule's actions and add them to the result list */
@@ -1003,22 +978,20 @@ fireRules(Query *parsetree,
1003978
1004979results = lappend (results ,rule_action );
1005980}
1006-
1007- /*
1008- * If this was an unqualified instead rule, throw away an
1009- * eventually saved 'default' parsetree
1010- */
1011- if (qsrc == QSRC_INSTEAD_RULE )
1012- * qual_products = NIL ;
1013981}
1014982
1015983return results ;
1016984}
1017985
1018986
1019-
987+ /*
988+ * One pass of rewriting a single query.
989+ *
990+ * parsetree is the input query. Return value and output parameters
991+ * are defined the same as for fireRules, above.
992+ */
1020993static List *
1021- RewriteQuery (Query * parsetree ,bool * instead_flag ,List * * qual_products )
994+ RewriteQuery (Query * parsetree ,bool * instead_flag ,Query * * qual_product )
1022995{
1023996CmdType event ;
1024997List * product_queries = NIL ;
@@ -1083,9 +1056,9 @@ RewriteQuery(Query *parsetree, bool *instead_flag, List **qual_products)
10831056product_queries = fireRules (parsetree ,
10841057result_relation ,
10851058event ,
1086- instead_flag ,
10871059locks ,
1088- qual_products );
1060+ instead_flag ,
1061+ qual_product );
10891062}
10901063
10911064heap_close (rt_entry_relation ,NoLock );/* keep lock! */
@@ -1099,7 +1072,7 @@ RewriteQuery(Query *parsetree, bool *instead_flag, List **qual_products)
10991072 * can be rewritten. Detecting cycles is left for the reader as an exercise.
11001073 */
11011074#ifndef REWRITE_INVOKE_MAX
1102- #define REWRITE_INVOKE_MAX 10
1075+ #define REWRITE_INVOKE_MAX 100
11031076#endif
11041077
11051078static int numQueryRewriteInvoked = 0 ;
@@ -1111,69 +1084,56 @@ static intnumQueryRewriteInvoked = 0;
11111084static List *
11121085deepRewriteQuery (Query * parsetree )
11131086{
1114- List * n ;
11151087List * rewritten = NIL ;
11161088List * result ;
1117- bool instead ;
1118- List * qual_products = NIL ;
1089+ bool instead = false;
1090+ Query * qual_product = NULL ;
1091+ List * n ;
11191092
11201093if (++ numQueryRewriteInvoked > REWRITE_INVOKE_MAX )
1121- {
11221094elog (ERROR ,"query rewritten %d times, may contain cycles" ,
11231095numQueryRewriteInvoked - 1 );
1124- }
11251096
1126- instead = false;
1127- result = RewriteQuery (parsetree ,& instead ,& qual_products );
1097+ result = RewriteQuery (parsetree ,& instead ,& qual_product );
11281098
11291099foreach (n ,result )
11301100{
11311101Query * pt = lfirst (n );
11321102List * newstuff ;
11331103
11341104newstuff = deepRewriteQuery (pt );
1135- if (newstuff != NIL )
1136- rewritten = nconc (rewritten ,newstuff );
1105+ rewritten = nconc (rewritten ,newstuff );
11371106}
11381107
11391108/*
11401109 * For INSERTs, the original query is done first; for UPDATE/DELETE,
11411110 * it is done last. This is needed because update and delete rule
11421111 * actions might not do anything if they are invoked after the update
11431112 * or delete is performed. The command counter increment between the
1144- * queryexecution makes the deleted (and maybe the updated) tuples
1113+ * queryexecutions makes the deleted (and maybe the updated) tuples
11451114 * disappear so the scans for them in the rule actions cannot find
11461115 * them.
1116+ *
1117+ * If we found any unqualified INSTEAD, the original query is not
1118+ * done at all, in any form. Otherwise, we add the modified form
1119+ * if qualified INSTEADs were found, else the unmodified form.
11471120 */
1148- if (parsetree -> commandType == CMD_INSERT )
1149- {
1150- /*
1151- * qual_products are the original query with the negated rule
1152- * qualification of an INSTEAD rule
1153- */
1154- if (qual_products != NIL )
1155- rewritten = nconc (qual_products ,rewritten );
1156-
1157- /*
1158- * Add the unmodified original query, if no INSTEAD rule was seen.
1159- */
1160- if (!instead )
1161- rewritten = lcons (parsetree ,rewritten );
1162- }
1163- else
1121+ if (!instead )
11641122{
1165- /*
1166- * qual_products are the original query with the negated rule
1167- * qualification of an INSTEAD rule
1168- */
1169- if (qual_products != NIL )
1170- rewritten = nconc (rewritten ,qual_products );
1171-
1172- /*
1173- * Add the unmodified original query, if no INSTEAD rule was seen.
1174- */
1175- if (!instead )
1176- rewritten = lappend (rewritten ,parsetree );
1123+ if (parsetree -> commandType == CMD_INSERT )
1124+ {
1125+ if (qual_product != NULL )
1126+ rewritten = lcons (qual_product ,rewritten );
1127+ else
1128+ rewritten = lcons (parsetree ,rewritten );
1129+ }
1130+ else
1131+ {
1132+ if (qual_product != NULL )
1133+ rewritten = lappend (rewritten ,qual_product );
1134+ else
1135+ rewritten = lappend (rewritten ,parsetree );
1136+ }
11771137}
11781138
11791139return rewritten ;