head 2.8; access; symbols release_4_2:2.8 aix_ok:2.7 Version_2_1:2.3 Except_for_ev_quals:2.1; locks; strict; comment @ * @; 2.8 date 94.02.07.11.41.02; author aoki; state Exp; branches; next 2.7; 2.7 date 93.09.22.01.27.47; author aoki; state Exp; branches; next 2.6; 2.6 date 91.11.12.23.22.32; author mer; state Exp; branches; next 2.5; 2.5 date 91.08.03.16.50.50; author glass; state Exp; branches; next 2.4; 2.4 date 91.07.30.07.36.59; author glass; state Exp; branches; next 2.3; 2.3 date 91.03.04.13.45.39; author mao; state Exp; branches; next 2.2; 2.2 date 90.11.02.11.03.29; author goh; state Exp; branches; next 2.1; 2.1 date 90.11.01.10.05.32; author goh; state Stab; branches; next 1.6; 1.6 date 90.11.01.09.45.44; author goh; state Exp; branches; next 1.5; 1.5 date 90.10.20.22.47.57; author goh; state Exp; branches; next 1.4; 1.4 date 90.10.16.12.37.37; author goh; state Exp; branches; next 1.3; 1.3 date 90.10.05.10.53.37; author goh; state Exp; branches; next 1.2; 1.2 date 90.10.03.16.52.43; author goh; state Exp; branches; next 1.1; 1.1 date 90.10.03.16.48.29; author goh; state Exp; branches; next ; desc @misc support routines for rewrite system @ 2.8 log @SearchSysCacheTuple called with wrong args (not enough, not cast right) @ text @/* ---------------------------------------------------------------- * FILE * RewriteSupport.c * * DESCRIPTION * * NOTES * * IDENTIFICATION * $Header: /faerie/aoki/postgres/src/backend/rewrite/RCS/RewriteSupport.c,v 2.7 1993/09/22 01:27:47 aoki Exp aoki $ * ---------------------------------------------------------------- */ #include "tmp/postgres.h" RcsId("$Header: /faerie/aoki/postgres/src/backend/rewrite/RCS/RewriteSupport.c,v 2.7 1993/09/22 01:27:47 aoki Exp aoki $"); #include "catalog/catname.h" #include "catalog/pg_rewrite.h" #include "catalog/syscache.h" /* for SearchSysCache */ #include "nodes/pg_lisp.h" /* for LispValue ... */ #include "utils/builtins.h" /* for textout */ #include "utils/rel.h" /* for Relation, RelationData ... */ #include "utils/log.h" /* for elog */ #include "storage/buf.h" /* for InvalidBuffer */ /* * RuleIdGetActionInfo * * given a rule oid, look it up and return * '(rule-event-qual (rule-parsetree_list)) * */ List RuleIdGetActionInfo ( ruleoid , instead_flag) OID ruleoid; int *instead_flag; { HeapTuple ruletuple; char *ruleaction = NULL; bool action_is_null = false; bool instead_is_null = false; Relation ruleRelation = NULL; TupleDescriptor ruleTupdesc = NULL; List ruleparse = NULL; char *rule_evqual_string = NULL; List rule_evqual = NULL; List i = NULL; int instead; ruleRelation = amopenr (RewriteRelationName); ruleTupdesc = RelationGetTupleDescriptor(ruleRelation); ruletuple = SearchSysCacheTuple (RULOID, (char *) ObjectIdGetDatum(ruleoid), (char *) NULL, (char *) NULL, (char *) NULL); if (ruletuple == NULL) elog(WARN, "rule %d isn't in rewrite system relation"); ruleaction = amgetattr ( ruletuple, InvalidBuffer, Anum_pg_rewrite_action, ruleTupdesc , &action_is_null ) ; rule_evqual_string = amgetattr (ruletuple, InvalidBuffer, Anum_pg_rewrite_ev_qual, ruleTupdesc , &action_is_null ) ; *instead_flag = (int) amgetattr (ruletuple, InvalidBuffer, Anum_pg_rewrite_is_instead, ruleTupdesc , &instead_is_null ) ; ruleaction = textout ((struct varlena *)ruleaction ); rule_evqual_string = textout((struct varlena *)rule_evqual_string); ruleparse = (List)StringToPlan(ruleaction); rule_evqual = (List)StringToPlan(rule_evqual_string); if ( action_is_null ) { printf ("action is empty !!!\n"); return ( LispNil ); } else { foreach ( i , ruleparse ) { #ifdef DEBUG /* Print_parse ( CAR(i) ); */ #endif } } amclose ( ruleRelation ); return (lispCons(rule_evqual,ruleparse)); } char * OperOidGetName ( oproid ) oid oproid; { HeapTuple oprtuple = NULL; OperatorTupleForm opform = NULL; oprtuple = SearchSysCacheTuple(OPROID, (char *) ObjectIdGetDatum(oproid), (char *) NULL, (char *) NULL, (char *) NULL); if ( oprtuple ) { opform = (OperatorTupleForm)GETSTRUCT(oprtuple); return ( (char *)&(opform->oprname)); } else { return ("bogus-operator"); } /*NOTREACHED*/ } @ 2.7 log @moved #includes around for portability @ text @d10 1 a10 1 * $Header: /data/01/postgres/src/backend/rewrite/RCS/RewriteSupport.c,v 2.6 1991/11/12 23:22:32 mer Exp $ d16 1 a16 1 RcsId("$Header$"); d53 4 a56 1 ruletuple = SearchSysCacheTuple ( RULOID, ruleoid ); d94 3 a96 1 oprtuple = SearchSysCacheTuple ( OPROID, oproid ); @ 2.6 log @casts to avoid prototype warns @ text @d4 3 a6 1 * d10 1 a10 1 * $Header: /users/mer/postgres/src/rewrite/RCS/RewriteSupport.c,v 2.5 1991/08/03 16:50:50 glass Exp mer $ d14 4 a19 1 #include "utils/rel.h" /* Relation, RelationData ... */ d21 1 d23 1 d25 2 @ 2.5 log @general cleanup @ text @d8 1 a8 1 * $Header: RCS/RewriteSupport.c,v 2.4 91/07/30 07:36:59 glass Exp Locker: glass $ d55 2 a56 2 ruleaction = textout (ruleaction ); rule_evqual_string = textout(rule_evqual_string); @ 2.4 log @added extra parameter to RuleIdGetActionInfo() for instead (?), and added some error checking @ text @d8 1 a8 1 * $Header: RCS/RewriteSupport.c,v 1.2 91/05/28 20:43:10 glass Exp Locker: glass $ d22 1 a22 1 * '(rule-event-qual rule-parsetree) @ 2.3 log @take out spurious fflush() calls @ text @d8 1 a8 1 * $Header: RCS/RewriteSupport.c,v 2.2 90/11/02 11:03:29 goh Exp Locker: mao $ d12 1 a13 1 d17 1 a17 1 d27 1 a27 1 RuleIdGetActionInfo ( ruleoid ) d29 1 d41 2 a42 2 ruleRelation = amopenr ("pg_rewrite"); d45 2 a46 1 d52 3 a54 1 d67 1 a67 1 Print_parse ( CAR(i) ); a70 1 @ 2.2 log @fixes problems with event qualifications @ text @d8 1 a8 1 * $Header: RCS/RewriteSupport.c,v 2.1 90/11/01 10:05:32 goh Stab $ a66 1 fflush(stdout); @ 2.1 log @stable version ; everything except ev_quals @ text @d8 1 a8 1 * $Header: RCS/RewriteSupport.c,v 1.6 90/11/01 09:45:44 goh Exp $ d19 1 a19 1 * RuleIdGetRuleParsetrees d21 2 a22 1 * given a rule oid, look it up and return the prs2text d37 2 a39 1 bool is_instead = false; d45 1 a45 1 ruleaction = amgetattr ( ruletuple, InvalidBuffer , Anum_pg_rewrite_action, d47 3 a50 4 is_instead = (bool)amgetattr ( ruletuple, InvalidBuffer , Anum_pg_rewrite_is_instead, ruleTupdesc, &instead_is_null ); d52 2 d55 2 a56 1 d70 1 a70 1 return (lispCons(is_instead,ruleparse)); @ 1.6 log @moved lock dependent stuff to locks.[ch] @ text @d8 1 a8 1 * $Header: RCS/RewriteSupport.c,v 1.2 90/11/01 09:37:22 goh Exp $ @ 1.5 log @support for event qualifications @ text @d8 1 a8 1 * $Header: RCS/RewriteSupport.c,v 1.4 90/10/16 12:37:37 goh Exp $ a11 2 #include "rules/prs2.h" #include "rules/prs2locks.h" a16 37 /* * RelationHasLocks * - returns true iff a relation has some locks on it */ RuleLock RelationGetRelationLocks ( relation ) Relation relation; { HeapTuple relationTuple; RuleLock relationLocks; relationTuple = SearchSysCacheTuple(RELNAME, &(RelationGetRelationTupleForm(relation)->relname), (char *) NULL, (char *) NULL, (char *) NULL); relationLocks = prs2GetLocksFromTuple( relationTuple, InvalidBuffer, (TupleDescriptor) NULL ); return(relationLocks); } bool RelationHasLocks ( relation ) Relation relation; { RuleLock relationLock = RelationGetRelationLocks (relation); if ( relationLock == NULL ) return (false ); else return ( true ); } @ 1.4 log @"versions now work" checkin @ text @d8 1 a8 1 * $Header: RCS/RewriteSupport.c,v 1.3 90/10/05 10:53:37 goh Exp Locker: goh $ d14 1 d65 1 a65 1 RuleIdGetRuleParsetrees ( ruleoid ) d71 1 d76 1 d78 1 a78 1 ruleRelation = amopenr ("pg_prs2rule"); d81 2 a82 1 ruleaction = amgetattr ( ruletuple, InvalidBuffer , 7 , d84 4 d105 1 a105 1 return (ruleparse); @ 1.3 log @removed extra #includes @ text @d8 1 a8 1 * $Header: RCS/RewriteSupport.c,v 1.2 90/10/03 16:52:43 goh Exp Locker: goh $ d100 16 @ 1.2 log @cleaned up extra code @ text @d3 1 a3 1 * RuleHandler.c d8 1 a8 1 * $Header: RCS/RewriteSupport.c,v 1.1 90/10/03 16:48:29 goh Exp Locker: goh $ a11 8 #include "tmp/postgres.h" #include "access/ftup.h"; #include "access/heapam.h" /* access methods like amopenr */ #include "access/htup.h" #include "access/itup.h" /* for T_LOCK */ #include "parser/atoms.h" #include "parser/parse.h" #include "parser/parsetree.h" a13 3 #include "utils/fmgr.h" #include "utils/log.h" #include "utils/rel.h" /* for Relation stuff */ d15 3 a17 8 #include "nodes/pg_lisp.h" #include "nodes/relation.h" #include "nodes/primnodes.a.h" #include "catalog/catname.h" #include "catalog/syscache.h" /* for SearchSysCache ... */ #include "catalog_utils.h" a22 1 extern RuleLock prs2GetLocksFromTuple(); d81 1 a81 1 ruleaction = fmgr (F_TEXTOUT,ruleaction ); d89 1 d91 1 @ 1.1 log @Initial revision @ text @d8 1 a8 1 * $Header: RCS/RuleHandler.c,v 1.10 90/09/21 11:18:17 goh Exp Locker: goh $ a12 19 /************************************************************* LockTypeRetrieveAction = "on retrieve do x" where x = {append,delete,replace} LockTypeRetrieveWrite = "on retrieve do x" where x = "replace current" LockTypeRetrieveRelation = "on retrieve do instead retrieve" #define LockTypeRetrieveAction ((Prs2LockType) 'r') #define LockTypeAppendAction ((Prs2LockType) 'a') #define LockTypeDeleteAction ((Prs2LockType) 'd') #define LockTypeReplaceAction ((Prs2LockType) 'u') #define LockTypeRetrieveWrite ((Prs2LockType) 'R') #define LockTypeAppendWrite ((Prs2LockType) 'A') #define LockTypeDeleteWrite ((Prs2LockType) 'D') #define LockTypeReplaceWrite ((Prs2LockType) 'U') #define LockTypeRetrieveRelation ((Prs2LockType) 'V') **************************************************************/ a34 1 extern LispValue TheseLocksWereTriggered ( /* RuleLock, LispValue */ ); a114 972 List RuleIdGetRuleParse (ruleoid) OID ruleoid; { /* XXX - assume only one parsetree */ elog(WARN,"calling unsupported routine RuleIdGetRuleParse"); return (CAR(RuleIdGetRuleParsetrees(ruleoid))); } /* * offset all the varnos in the rule parsetree by length * of the user parsetree - 2 ( -2 is because of current and new ) * */ OffsetAllVarNodes ( trigger_varno, parsetree, offset ) int trigger_varno; List parsetree; int offset; { List i; foreach ( i , parsetree ) { Node thisnode = (Node)CAR(i); if ( thisnode && IsA(thisnode,Var)) { if (get_varno (thisnode) == 1) { /* *CURRENT* */ printf("taking care of a varnode pointing to *CURRENT*"); set_varno ( thisnode, trigger_varno ); CAR ( get_varid (thisnode) ) = lispInteger ( trigger_varno ); /* XXX - should fix the varattno too !!! */ } else if (get_varno(thisnode) == 2 ) { /* *NEW* * * should take the right side out of the corresponding * targetlist entry from the user query * and stick it here */ elog(NOTICE,"NEW not properly taken care of"); } else { set_varno ( thisnode, get_varno(thisnode) + offset ); CAR( get_varid ( thisnode ) ) = lispInteger (get_varno(thisnode) ); } } if ( thisnode && IsA(thisnode,Param) ) { /* currently only *CURRENT* */ } if ( thisnode && thisnode->type == PGLISP_DTPR ) OffsetAllVarNodes(trigger_varno,(List)thisnode,offset); } } /* * ChangeTheseVars * * varno,varattno - varno and varattno of Var node must match this * to qualify for change * parser_subtree - tree to iterate over * lock - the lock which caused this rewrite */ ChangeTheseVars ( varno, varattno, parser_subtree, replacement ) int varno; AttributeNumber varattno; List parser_subtree; List replacement; { List i = NULL; foreach ( i , parser_subtree ) { Node temp = (Node)CAR(i); if (IsA(temp,Var) && ((get_varattno((Var)temp) == varattno )|| (varattno == -1 )) && (get_varno((Var)temp) == varno ) ) { CAR(i) = replacement; /* CDR(last(replacement)) = CDR(i); CDR(i) = CDR(replacement); */ } if ( temp->type == PGLISP_DTPR ) ChangeTheseVars ( varno, varattno, (List)temp, replacement ); } } ReplaceVarWithMulti ( varno, attno, parser_subtree, replacement ) int varno; AttributeNumber attno; List parser_subtree; List replacement; { List i = NULL; List vardotfields = NULL; List saved = NULL; foreach ( i , parser_subtree ) { Node temp = (Node)CAR(i); if (IsA(temp,Var) && get_varattno((Var)temp) == attno && get_varno((Var)temp) == varno ) { elog (NOTICE, "now replacing ( %d %d )",varno,attno); vardotfields = get_vardotfields ( temp ); if ( vardotfields != NULL ) { /* a real postquel procedure invocation */ List j = NULL; foreach ( j , replacement ) { List rule_tlentry = CAR(j); Resdom rule_resdom = (Resdom)CAR(rule_tlentry); List rule_tlexpr = CDR(rule_tlentry); Name rule_resdom_name = get_resname ( rule_resdom ); char *var_dotfields_firstname = NULL; var_dotfields_firstname = CString ( CAR ( vardotfields ) ); if ( !strcmp ( rule_resdom_name, var_dotfields_firstname ) ) { if ( saved && saved->type == PGLISP_DTPR && IsA(CAR(saved),Resdom) && get_restype (CAR(saved)) != get_restype (rule_resdom) ) { set_restype (CAR(saved), get_restype(rule_resdom)); set_reslen (CAR(saved), get_reslen(rule_resdom)); } CAR(i) = CAR(rule_tlexpr); CDR(i) = CDR(rule_tlexpr); } } } else { /* no dotfields, so retrieve text ??? */ List j = NULL; foreach ( j , replacement ) { List rule_tlentry = CAR(j); /* Resdom rule_resdom = (Resdom)CAR(rule_tlentry); */ List rule_tlexpr = CDR(rule_tlentry); /* Name rule_resdom_name = get_resname ( rule_resdom );*/ CAR(i) = CAR(rule_tlexpr); CDR(i) = CDR(rule_tlexpr); } } /* vardotfields != NULL */ } if ( temp->type == PGLISP_DTPR ) ReplaceVarWithMulti ( varno, attno, (List)temp, (List)replacement ); saved = i; } } StickOnUpperAndLower ( user, rule ) List user; List rule; { List i = NULL; foreach ( i , rule ) { List entry = CAR(i); if ((! strcmp ( get_resname (CAR(entry)), "u") ) || (! strcmp ( get_resname (CAR(entry)), "l") ) ) CDR(last(user)) = lispCons ( entry, LispNil ); } } /* * walk the targetlist, * fixing the resnodes resnos * as well as removing "extra" resdoms * caused by the replacement of varnodes by * entire "targetlists" */ FixResdom ( targetlist ) List targetlist; { List i; int res_index = 1; foreach ( i , targetlist ) { List tle = CAR(i); if (CADR(tle)->type == PGLISP_DTPR && IsA (CAR(CADR(tle)),Resdom)) { CAR(i) = CADR(tle); CDR(last(CDR(tle))) = CDR(i); CDR(i) = CDR(CDR(tle)); } } foreach ( i , targetlist ) { List tle = CAR(i); Resdom res = (Resdom)CAR(tle); set_resno(res,res_index++); } } /* * 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 */ bool ThisLockWasTriggered ( varno, attnum, parse_subtree ) int varno; AttributeNumber attnum; List parse_subtree; { List i; foreach ( i , parse_subtree ) { Node temp = (Node)CAR(i); if ( !null(temp) && IsA(temp,Var) && ( varno == get_varno((Var)temp)) && (( get_varattno((Var)temp) == attnum ) || attnum == -1 ) ) return ( true ); if ( temp && temp->type == PGLISP_DTPR && ThisLockWasTriggered ( varno, attnum, (List) temp ) ) return ( true ); } return ( false ); } /* * MatchRetrieveLocks * - looks for varnodes that match the rulelock * (where match(foo) => varno = foo.varno AND * ( (oneLock->attNum == -1) OR * (oneLock->attNum = foo.varattno )) * * RETURNS: list of rulelocks * XXX can be improved by searching for all locks * at once by NOT calling ThisLockWasTriggered */ List MatchRetrieveLocks ( rulelocks , parse_subtree , varno ) RuleLock rulelocks; List parse_subtree; int varno; { int nlocks = 0; int i = 0; Prs2OneLock oneLock = NULL; List real_locks = NULL; Assert ( rulelocks != NULL ); nlocks = prs2GetNumberOfLocks ( rulelocks ); Assert (nlocks <= 16 ); for ( i = 0 ; i < nlocks ; i++ ) { oneLock = prs2GetOneLockFromLocks ( rulelocks , i ); if ( oneLock->lockType == LockTypeRetrieveAction || oneLock->lockType == LockTypeRetrieveWrite || oneLock->lockType == LockTypeRetrieveRelation ) { if ( ThisLockWasTriggered ( varno, oneLock->attributeNumber, parse_subtree )) real_locks = lispCons ( oneLock , real_locks ); } } return ( real_locks ); } LispValue TheseLocksWereTriggered ( rulelocks , parse_subtree, event_type , varno ) RuleLock rulelocks; List parse_subtree; int event_type; int varno; { int nlocks = 0; int i = 0; Prs2OneLock oneLock = NULL; /* int j = 0;*/ List real_locks = NULL; Assert ( rulelocks != NULL ); nlocks = prs2GetNumberOfLocks ( rulelocks ); Assert (nlocks <= 16 ); for ( i = 0 ; i < nlocks ; i++ ) { oneLock = prs2GetOneLockFromLocks ( rulelocks, i ); switch ( oneLock->lockType ) { case LockTypeRetrieveAction: case LockTypeRetrieveWrite: if (( event_type == RETRIEVE ) && ( ThisLockWasTriggered ( varno, oneLock->attributeNumber , parse_subtree )) ) { real_locks = lispCons ( oneLock, real_locks ); } else { continue; } case LockTypeInvalid: case LockTypeAppendAction: case LockTypeDeleteAction: case LockTypeReplaceAction: case LockTypeAppendWrite: case LockTypeDeleteWrite: case LockTypeReplaceWrite: continue; /* skip the rest of the stuff in this iteration */ } /* switch */ } /* for */ return ( real_locks ); } Print_quals ( quals ) List quals; { printf("\nQualifications = \n"); lispDisplay(quals,0); fflush(stdout); } Print_targetlist ( tlist ) List tlist; { printf("\nTargetlist = \n"); lispDisplay(tlist,0); fflush(stdout); } Print_rangetable ( rtable ) List rtable; { printf("\nRangetable = \n"); lispDisplay(rtable,0); fflush(stdout); } Print_parse ( parsetree ) List parsetree; { List quals = parse_qualification(parsetree); List tlist = parse_targetlist(parsetree); List rtable = root_rangetable (parse_root (parsetree)); Print_rangetable(rtable); Print_targetlist(tlist); Print_quals(quals); fflush(stdout); } void PrintRuleLock ( rlock ) Prs2OneLock rlock; { printf("#S(RuleLock "); printf(":rulid %ld ",rlock->ruleId); printf(":locktype %c ", rlock->lockType ); printf(":attnum %d )", rlock->attributeNumber ); fflush(stdout); } void PrintRuleLockList ( rlist ) List rlist; { Prs2OneLock temp = NULL; List j = NULL; foreach ( j , rlist ) { temp = (Prs2OneLock)CAR(j); PrintRuleLock ( temp ); } printf("\n"); } /* * AddQualifications * - takes a parsetree, and a new qualification * and adds the new qualification onto the parsetree * * MODIFIES: parsetree */ void AddQualifications ( parsetree , new_qual ) List parsetree; List new_qual; { if ( parse_qualification(parsetree) == NULL ) parse_qualification(parsetree) = new_qual; else parse_qualification ( parsetree ) = lispCons ( lispInteger(AND), lispCons ( parse_qualification(parsetree), lispCons ( new_qual, LispNil ))); } List ModifyVarNodes( retrieve_locks , user_rt_length , current_varno , to_be_rewritten , user_tl , user_rt ,user_parsetree ) List retrieve_locks; int user_rt_length; int current_varno; Relation to_be_rewritten; List user_tl; List user_rt; List user_parsetree; { List i = NULL; List j = NULL; List k = NULL; List ruletrees = NULL; List additional_queries = NULL; /* set by locktyperetrieveaction */ foreach ( i , retrieve_locks ) { Prs2OneLock this_lock = (Prs2OneLock)CAR(i); List rule_tlist = NULL; List rule_qual = NULL; List rule_rangetable = NULL; int result_rtindex = 0 ; char *result_relname = NULL; List result_rte = NULL; ruletrees = RuleIdGetRuleParsetrees ( this_lock->ruleId ); foreach ( j , ruletrees ) { List ruleparse = CAR(j); Assert (ruleparse != NULL ); rule_tlist = parse_targetlist(ruleparse); rule_qual = parse_qualification(ruleparse); rule_rangetable = root_rangetable(parse_root (ruleparse)); if ( this_lock->attributeNumber == -1 ) elog(NOTICE, "firing a multi-attribute rule"); OffsetAllVarNodes ( current_varno, ruleparse, user_rt_length -2 ); switch ( this_lock->lockType ) { case LockTypeRetrieveWrite: /* ON RETRIEVE DO REPLACE CURRENT */ elog ( NOTICE, "replace current action"); Print_parse ( ruleparse ); result_rtindex = CInteger(root_result_relation(parse_root(ruleparse ))); result_rte = nth ( result_rtindex -1 , rule_rangetable ); result_relname = CString ( CAR ( result_rte )); if ( strcmp ( result_relname,"*CURRENT*")) elog(WARN,"a on-retr-do-repl rulelock with bogus result"); foreach ( k , rule_tlist ) { List tlist_entry = CAR(k); Resdom tlist_resdom = (Resdom)CAR(tlist_entry); List tlist_expr = CADR(tlist_entry); char *attname = (char *) get_resname ( tlist_resdom ); int attno; elog ( NOTICE, "replacing %s", attname ); attno = varattno ( to_be_rewritten, attname ); ChangeTheseVars ( current_varno, attno, user_tl, tlist_expr ); } /* foreach */ break; case LockTypeRetrieveRelation: /* now stuff the entire targetlist * into this one varnode, filtering * out according to whatever is * in vardotfields * NOTE: used only by procedures ??? */ elog(NOTICE,"retrieving procedure result fields"); ReplaceVarWithMulti ( current_varno, this_lock->attributeNumber, user_tl, rule_tlist ); printf ("after replacing tlist entry :\n"); lispDisplay ( user_tl, 0 ); fflush(stdout); result_relname = ""; FixResdom ( user_tl ); break; case LockTypeRetrieveAction: elog(NOTICE,"retrieve triggering other actions"); elog(NOTICE,"does not modify existing parsetree"); break; default: elog(WARN,"on retrieve do , action unknown"); } /* add the additional rt_entries */ CDR(last(user_rt)) = CDR(CDR(rule_rangetable)); /* XXX - clean up redundant rt_entries ??? */ AddQualifications ( user_parsetree , rule_qual ); printf ("\n"); printf ("*************************\n"); printf (" Modified User Parsetree\n"); printf ("*************************\n"); Print_parse ( user_parsetree ); } /* foreach of the ruletrees */ } /* foreach of the locks */ return ( additional_queries ); } List ModifyDeleteQueries( drop_user_query ) bool *drop_user_query; { return(NULL); } List MatchDeleteLocks ( ) { } /* * MatchUpdateLocks * - match the list of locks, */ List MatchUpdateLocks ( command , rulelocks , current_varno , user_parsetree ) int command; RuleLock rulelocks; int current_varno; List user_parsetree; { List real_locks = NULL; Prs2OneLock oneLock = NULL; int nlocks = 0; int i = 0; List actual_replace_reln = NULL; Assert ( rulelocks != NULL ); /* we get called iff there is some lock */ if ( command != REPLACE && command != APPEND ) return ( NULL ); /* * if we reach the following statement, the * user_command must be a replace or append * XXX - (does it matter which ???) */ Assert ( user_parsetree != NULL ); actual_replace_reln = root_result_relation ( parse_root ( user_parsetree ) ); if ( CInteger ( actual_replace_reln ) != current_varno ) { return ( real_locks ); } nlocks = prs2GetNumberOfLocks ( rulelocks ); Assert (nlocks <= 16 ); for ( i = 0 ; i < nlocks ; i++ ) { oneLock = prs2GetOneLockFromLocks ( rulelocks , i ); if ( oneLock->lockType == LockTypeReplaceAction || oneLock->lockType == LockTypeAppendAction ) { real_locks = lispCons ( oneLock , real_locks ); } /* if lock is suitable */ } /* for all locks */ return ( real_locks ); } List FindMatchingNew ( user_parsetree , attno ) List user_parsetree; int attno; { List tlist = parse_targetlist(user_parsetree); List i = NULL; foreach ( i , tlist ) { List one_entry = CAR(i); List entry_LHS = CAR(one_entry); Assert(IsA(entry_LHS,Resdom)); if ( get_resno(entry_LHS) == attno ) { return ( CDR(one_entry)); } } return ( NULL ); /* could not find a matching RHS */ } List HandleVarNodes ( parse_subtree , user_parsetree , trigger_varno, offset ) List parse_subtree; List user_parsetree; int trigger_varno; int offset; { List i = NULL; foreach ( i , parse_subtree ) { Node thisnode = (Node)CAR(i); if ( thisnode && IsA(thisnode,Var)) { List matched_new = NULL; switch ( get_varno(thisnode)) { case 2: /* *NEW* * * should take the right side out of the corresponding * targetlist entry from the user query * and stick it here */ matched_new = FindMatchingNew ( user_parsetree , get_varattno ( thisnode )); if ( matched_new ) { CAR(i) = matched_new; break; } /* if no match, then fall thru to current */ case 1: /* *CURRENT* */ printf("replacing *CURRENT* or unmatch *NEW*"); set_varno ( thisnode, trigger_varno ); CAR ( get_varid (thisnode) ) = lispInteger ( trigger_varno ); /* XXX - should fix the varattno too !!! */ break; default: set_varno ( thisnode, get_varno(thisnode) + offset ); CAR( get_varid ( thisnode ) ) = lispInteger (get_varno(thisnode) ); } /* end switch */ } /* is a Var */ if ( thisnode && thisnode->type == PGLISP_DTPR ) HandleVarnodes( (List)thisnode, user_parsetree, trigger_varno,offset); } } ModifyUpdateTlist( tlist , user_parsetree , current_varno ) List tlist; List user_parsetree; int current_varno; { List i = NULL; int new_trigger_varno = current_varno + length(tlist) - 2; /* replace #S(Var :varno2 ...) with corresponding RHS of * tlist expression from user_parsetree */ foreach ( i , tlist ) { List this_entry = CAR(i); Resdom this_resdom = (Resdom)CAR(this_entry); List original_rhs = CDR(this_entry); List new_rhs = NULL; new_rhs = HandleVarNodes ( original_rhs , user_parsetree , new_trigger_varno, -2 ); CDR(this_entry) = new_rhs; } } /* * ModifyUpdateNodes * RETURNS: list of additional parsetrees * MODIFIES: original parsetree, drop_user_query * STRATEGY: * foreach rule-action { * action = copy(rule-action); * foreach ( resdom in user_tlist ) { * */ List ModifyUpdateNodes( update_locks , user_parsetree, drop_user_query ,current_varno ) List update_locks; List user_parsetree; bool *drop_user_query; int current_varno; { List i = NULL; List j = NULL; List new_queries = NULL; List ruletrees = NULL; Assert ( update_locks != NULL ); /* otherwise we won't have been called */ /* XXX - for now, instead is always true */ *drop_user_query = true; foreach ( i , update_locks ) { Prs2OneLock this_lock = (Prs2OneLock)CAR(i); printf ("\nNow processing :"); PrintRuleLock ( this_lock ); ruletrees = RuleIdGetRuleParsetrees ( this_lock->ruleId ); foreach ( j , ruletrees ) { List rule_action = CAR(j); List rule_tlist = parse_targetlist(rule_action); ModifyUpdateTlist( rule_tlist , user_parsetree , current_varno ); #ifdef NOTYET /* add the additional rt_entries */ CDR(last(rule_rt)) = CDR(CDR(user_rt)); AddQualification(final_action, parse_qualification(user_parsetree)); #endif new_queries = nappend1 ( new_queries, rule_action ); } } return(new_queries); } /* * ProcessOneLock * - process a single rangetable entry * * RETURNS: a list of additional queries that need to be executed * MODIFIES: current qual or tlist * */ List ProcessOneLock ( user_parsetree , reldesc , user_rangetable , current_varno , command , drop_user_query ) List user_parsetree; Relation reldesc; List user_rangetable; int current_varno; int command; bool *drop_user_query; { RuleLock rlocks = NULL; List retrieve_locks = NULL; List update_locks = NULL; List delete_locks = NULL; List additional_queries = NULL; List user_tlist = parse_targetlist(user_parsetree); #ifdef NOTYET List user_qual = parse_qualification(user_parsetree); #endif rlocks = RelationGetRelationLocks ( reldesc ); if ( rlocks == NULL ) { /* this relation (rangevar) has no locks on it, so * return without either modifying the user query * or generating a new (extra) query */ return ( NULL ); } /* * MATCH RETRIEVE RULES HERE (regardless of current command type) * a varnode that matches the current varno and the varattno matches * "rlocks" attnum ( where match means = if attnum is > 0 or always true * if attnum = -1 ) */ retrieve_locks = MatchRetrieveLocks ( rlocks , user_parsetree , current_varno ); if ( retrieve_locks ) { printf ( "\nThese retrieve rules were triggered: \n"); PrintRuleLockList ( retrieve_locks ); additional_queries = ModifyVarNodes ( retrieve_locks, length ( user_rangetable ), current_varno, reldesc, user_tlist, user_rangetable, user_parsetree ); } /* * drop_user_query IS NOT SET in this routine * because "retrieve" rules when operating on qualifications * modify the user_parsetree, therefore, the "instead"ness * of the rule is satisfied. * * XXX - right now, retrieve rules cannot be of the "also" * type because Postgres does not support union'ed qualifiers * so, for example the rule : * on retrieve to toy * do retrieve ( emp.all ) where emp.dept = "toy" * which theoretically should produce the partially materialized * view "toy", of which some tuples are really in "toy" and * others in "emp", does not really work. */ switch (command) { case RETRIEVE: /* do nothing since it is handled above */ break; case DELETE: /* no targetlist, so handled differently */ delete_locks = MatchDeleteLocks (); additional_queries = append ( additional_queries, ModifyDeleteQueries( drop_user_query ) ); break; case APPEND: case REPLACE: update_locks = MatchUpdateLocks ( command , rlocks , current_varno, user_parsetree ); if ( update_locks ) { List new_queries = NULL; printf ( "\nUpdate triggered the following locks:\n"); PrintRuleLockList ( update_locks ); new_queries = ModifyUpdateNodes( update_locks, user_parsetree, drop_user_query, current_varno); additional_queries = append (additional_queries, new_queries ); } break; } /* when we get here, additional queries is either null * (no additional queries) OR additional queries is a list * of rule generated queries (in addition to the user query) * NOTE: at this point, the original user query * may have mutated beyond recognition * ALSO: what do we do if the retrieve rule says "instead" * but another rule ( that is also active on this query ) doesn't */ return ( additional_queries ); } List QueryRewrite ( parsetree ) List parsetree; { List user_root = NULL; List user_rangetable = NULL; int user_command ; List output_parselist = NULL; List user_rtentry_ptr = NULL; List user_tl = NULL; List user_qual = NULL; int user_rt_length = 0; int this_relation_varno = 1; /* varnos start with 1 */ bool drop_user_query = false; /* unless ProcessOneLock * modifies this, we * add on the user_query * in front of all queries */ Assert ( parsetree != NULL ); Assert ( (user_root = parse_root(parsetree)) != NULL ); user_rangetable = root_rangetable(user_root); user_command = root_command_type ( user_root ); user_rt_length = length ( user_rangetable ); /* * only for a delete may the targetlist be NULL */ if ( user_command != DELETE ) Assert ( (user_tl = parse_targetlist(parsetree)) != NULL ); user_qual = parse_qualification(parsetree); /* may be NULL */ foreach ( user_rtentry_ptr , user_rangetable ) { List user_rtentry = CAR(user_rtentry_ptr); Name this_rtname = NULL; Relation this_relation = NULL; this_rtname = (Name)CString( CADR ( user_rtentry )); this_relation = amopenr ( this_rtname ); Assert ( this_relation != NULL ); elog(NOTICE,"checking for locks on %s", this_rtname ); if ( RelationHasLocks ( this_relation )) { List additional_queries = NULL; List additional_query = NULL; /* * ProcessOneLock _may_ modify the contents * of "user_qual" or "user_tl" and "user_rangetable" if * the rule referenced by the lock has a "do instead" * clause */ additional_queries = ProcessOneLock ( parsetree, this_relation, user_rangetable, this_relation_varno++ , user_command , &drop_user_query ); if ( drop_user_query == false && additional_queries != NULL ) { /* start the output parse list with the * user query since no qualifying * "instead" clauses were found */ output_parselist = lispCons ( parsetree, LispNil ); } if ( additional_queries != NULL ) { List i = NULL; foreach ( i , additional_queries ) { List new_parsetree = CAR(i); List new_rewritten = NULL; if ( new_parsetree != NULL ) new_rewritten = QueryRewrite ( new_parsetree ); if ( new_rewritten == NULL ) { /* if nothing in fact got changed */ nappend1 ( output_parselist , new_parsetree ); } else { output_parselist = append ( output_parselist, new_rewritten ); } } /* rewrite any new queries */ } /* if there are new queries */ } } return ( output_parselist ); } @