head 2.19; access; symbols Version_2_1:2.5 Except_for_ev_quals:2.1; locks; strict; comment @ * @; 2.19 date 92.08.03.23.28.46; author glass; state Exp; branches; next 2.18; 2.18 date 92.07.07.23.39.55; author joey; state Exp; branches; next 2.17; 2.17 date 92.07.07.22.20.34; author glass; state Exp; branches; next 2.16; 2.16 date 92.07.04.04.03.32; author mao; state Exp; branches; next 2.15; 2.15 date 91.11.17.21.08.16; author mer; state Exp; branches; next 2.14; 2.14 date 91.11.07.19.44.46; author glass; state Exp; branches; next 2.13; 2.13 date 91.08.16.03.54.31; author glass; state Exp; branches; next 2.12; 2.12 date 91.08.16.03.21.33; author glass; state Exp; branches; next 2.11; 2.11 date 91.08.15.05.46.36; author glass; state Exp; branches; next 2.10; 2.10 date 91.08.09.00.44.03; author glass; state Exp; branches; next 2.9; 2.9 date 91.08.08.18.36.14; author glass; state Exp; branches; next 2.8; 2.8 date 91.08.03.16.49.08; author glass; state Exp; branches; next 2.7; 2.7 date 91.07.30.07.41.56; author glass; state Exp; branches; next 2.6; 2.6 date 91.03.18.21.00.42; author sp; state Exp; branches; next 2.5; 2.5 date 91.02.26.18.48.27; author sp; state Exp; branches; next 2.4; 2.4 date 91.02.24.21.41.42; author mao; state Exp; branches; next 2.3; 2.3 date 91.02.02.15.03.29; author sp; state Exp; branches; next 2.2; 2.2 date 90.11.02.11.03.32; author goh; state Exp; branches; next 2.1; 2.1 date 90.11.01.10.05.29; author goh; state Stab; branches; next 1.2; 1.2 date 90.10.18.17.09.36; author goh; state Exp; branches; next 1.1; 1.1 date 90.10.04.09.56.12; author goh; state Exp; branches; next ; desc @parsetree manipulation stuff for query rewrite @ 2.19 log @fix stupid prohibition involving append events and delete/retrieve actions in rules. @ text @/* * $Header: /home/postgres/glass/RCS/RewriteManip.c,v 2.18 1992/07/07 23:39:55 joey Exp glass $ */ #include "nodes/pg_lisp.h" #include "tmp/c.h" #include "utils/log.h" #include "nodes/nodes.h" #include "nodes/relation.h" #include "rules/prs2locks.h" /* prs2 lock definitions */ #include "rules/prs2.h" /* prs2 routine headers */ #include "nodes/primnodes.h" #include "nodes/primnodes.a.h" #include "parser/parsetree.h" #include "parser/parse.h" #include "utils/lsyscache.h" #include "./RewriteHandler.h" #include "./RewriteSupport.h" #include "./locks.h" #include "nodes/plannodes.h" #include "nodes/plannodes.a.h" extern List copy_seq_tree(); extern Const RMakeConst(); extern List lispCopy(); void OffsetVarNodes ( qual_or_tlist , offset ) List qual_or_tlist; int offset; { List i = NULL; foreach ( i , qual_or_tlist ) { Node this_node = (Node)CAR(i); if ( this_node ) { switch ( NodeType (this_node)) { case classTag(LispList): OffsetVarNodes ( (List)this_node , offset ); break; case classTag(Var): { int this_varno = (int)get_varno ( (Var) this_node ); int new_varno = this_varno + offset; set_varno ( (Var) this_node , new_varno ); CAR(get_varid ( (Var) this_node)) = lispInteger ( new_varno ); break; } default: /* ignore the others */ break; } /* end switch on type */ } /* if not null */ } /* foreach element in subtree */ } void ChangeVarNodes ( qual_or_tlist , old_varno, new_varno) List qual_or_tlist; int old_varno, new_varno; { List i = NULL; foreach ( i , qual_or_tlist ) { Node this_node = (Node)CAR(i); if ( this_node ) { switch ( NodeType (this_node)) { case classTag(LispList): ChangeVarNodes ( (List)this_node , old_varno, new_varno); break; case classTag(Var): { int this_varno = (int)get_varno ( (Var) this_node ); if (this_varno == old_varno) { set_varno ((Var) this_node, new_varno); CAR(get_varid ( (Var) this_node)) = lispInteger ( new_varno ); } break; } default: /* ignore the others */ break; } /* end switch on type */ } /* if not null */ } /* foreach element in subtree */ } void AddQual(parsetree, qual) List parsetree,qual; { List copy,old; if (qual == NULL) return; copy = copy_seq_tree (qual); old = parse_qualification(parsetree); if (old == NULL) parse_qualification(parsetree) = copy; else parse_qualification(parsetree) = lispCons(lispInteger(AND), lispCons(parse_qualification(parsetree), lispCons(copy,LispNil))); } void AddNotQual(parsetree, qual) List parsetree,qual; { List copy,old; if (qual == NULL) return; copy = lispCons(lispInteger(NOT), lispCons(copy_seq_tree(qual), LispNil)); AddQual(parsetree,copy); } static List make_null(type) ObjectId type; { Const c; c = RMakeConst(); set_consttype(c, type); set_constlen(c, (Size) get_typlen(type)); set_constvalue(c, PointerGetDatum(NULL)); set_constisnull(c, true); set_constbyval(c, get_typbyval(type)); return lispCons((LispValue)c,LispNil); } void FixResdomTypes (user_tlist) List user_tlist; { List i; foreach ( i , user_tlist ) { List one_entry = CAR(i); List entry_LHS = CAR(one_entry); List entry_RHS = CAR(CDR(one_entry)); Assert(IsA(entry_LHS,Resdom)); if (NodeType(entry_RHS) == classTag(Var)) { set_restype((Resdom) entry_LHS, get_vartype((Var) entry_RHS)); set_reslen ((Resdom) entry_LHS, get_typlen(get_vartype((Var) entry_RHS))); } } } static List FindMatchingNew ( user_tlist , attno ) List user_tlist; int attno; { List i = LispNil; foreach ( i , user_tlist ) { List one_entry = CAR(i); List entry_LHS = CAR(one_entry); Assert(IsA(entry_LHS,Resdom)); if ( get_resno((Resdom) entry_LHS) == attno ) { return ( CDR(one_entry)); } } return LispNil; /* could not find a matching RHS */ } static List FindMatchingTLEntry ( user_tlist , e_attname) List user_tlist; Name e_attname; { List i = LispNil; foreach ( i , user_tlist ) { List one_entry = CAR(i); List entry_LHS = CAR(one_entry); Name foo; Resdom x; Assert(IsA(entry_LHS,Resdom)); x = (Resdom) entry_LHS; foo = get_resname((Resdom) entry_LHS); if (!strcmp(foo, e_attname)) return ( CDR(one_entry)); } return LispNil ; /* could not find a matching RHS */ } void ResolveNew(info, targetlist,tree) RewriteInfo *info; List targetlist; List tree; { List i,n; foreach ( i , tree) { List this_node = CAR(i); if ( this_node ) { switch ( NodeType (this_node)) { case classTag(LispList): ResolveNew (info, targetlist, (List)this_node); break; case classTag(Var): { int this_varno = (int)get_varno ( (Var) this_node ); if ((this_varno == info->new_varno) ) { n = FindMatchingNew (targetlist , get_varattno((Var) this_node)); if (n == LispNil) { if (info->event == REPLACE) { set_varno((Var) this_node, info->current_varno); } else { n = (List) make_null(get_vartype((Var) this_node)); CAR(i) = CAR(n); /* CDR(i) = CDR(n);*/ } } else { CAR(i) = CAR(n); /* CDR(i) = CDR(n);*/ } } break; } default: /* ignore the others */ break; } /* end switch on type */ } /* foreach element in subtree */ } } void FixNew(info, parsetree) List parsetree; RewriteInfo *info; { /* if ((info->action == DELETE) || (info->action == RETRIEVE)) return;*/ ResolveNew(info,parse_targetlist(parsetree),info->rule_action); } /* * Handles 'on retrieve to relation.attribute * do instead retrieve (attribute = expression) w/qual' */ void HandleRIRAttributeRule(parsetree, rt,tl, rt_index, attr_num,modified, badpostquel) List rt; List parsetree, tl; int rt_index, attr_num,*modified,*badpostquel; { List entry, entry_LHS; List i,n; foreach ( i , parsetree) { List this_node = CAR(i); if ( this_node ) { switch ( NodeType (this_node)) { case classTag(LispList): HandleRIRAttributeRule(this_node, rt,tl, rt_index, attr_num, modified,badpostquel); break; case classTag(Var): { int this_varno = (int)get_varno ( (Var) this_node ); char *name_to_look_for = NULL; if (this_varno == rt_index && get_varattno((Var) this_node) == attr_num) { if (get_vartype((Var) this_node) == 32) { /* HACK */ n = (List) make_null(get_vartype((Var) this_node)); CAR(i) = CAR(n); *modified = TRUE; *badpostquel = TRUE; break; } else { name_to_look_for = (char *) get_attname(CInteger(getrelid(this_varno, rt)), attr_num); } } if (name_to_look_for) { n = FindMatchingTLEntry(tl,name_to_look_for); if (n == NULL) n = (List) make_null(get_vartype((Var) this_node)); CAR(i) = CAR(n); *modified = TRUE; } break; } default: /* ignore the others */ break; } /* end switch on type */ } /* foreach element in subtree */ } } void HandleViewRule(parsetree, rt,tl, rt_index,modified) List parsetree, tl,rt; int rt_index,*modified; { List i,n; foreach ( i , parsetree) { List this_node = CAR(i); if ( this_node ) { switch ( NodeType (this_node)) { case classTag(LispList): HandleViewRule((List) this_node, rt, tl, rt_index,modified); break; case classTag(Var): { int this_varno = (int)get_varno ( (Var) this_node ); if (this_varno == rt_index) { Var x = (Var) this_node; n = FindMatchingTLEntry (tl, get_attname(CInteger(getrelid(this_varno,rt)), get_varattno(x))); if (n == NULL) n = (List) make_null(get_vartype((Var) this_node)); CAR(i) = CAR(n); /* CDR(i) = CDR(n);*/ *modified = TRUE; } } break; default: /* ignore the others */ break; } /* end switch on type */ } /* foreach element in subtree */ } } @ 2.18 log @fix a Glassian typo @ text @d2 1 a2 1 * $Header: /private/joey/pg/src/rewrite/RCS/RewriteManip.c,v 2.17 1992/07/07 22:20:34 glass Exp joey $ d239 1 a239 1 if ((info->action == DELETE) || (info->action == RETRIEVE)) return; @ 2.17 log @unbroke something munged in vardotfields removal removed secondary "why did it ever work"? @ text @d2 1 a2 1 * $Header: /home/postgres/glass/RCS/RewriteManip.c,v 2.16 1992/07/04 04:03:32 mao Exp glass $ d287 1 a287 1 *Modified = TRUE; @ 2.16 log @fixes for arrays, array refs, and nested dots @ text @d2 1 a2 1 * $Header: /private/mao/postgres/src/rewrite/RCS/RewriteManip.c,v 2.15 1991/11/17 21:08:16 mer Exp mao $ d265 3 a267 3 char *name_to_look_for; if (this_varno != rt_index && get_varattno((Var) this_node) != attr_num) { d282 1 d287 1 a287 1 *modified = TRUE; d290 1 @ 2.15 log @prototyping @ text @d2 1 a2 1 * $Header: /users/mer/postgres/src/rewrite/RCS/RewriteManip.c,v 2.14 1991/11/07 19:44:46 glass Exp mer $ a264 1 List vardots = get_vardotfields((Var) this_node); d266 2 a267 6 if (this_varno == rt_index && get_varattno((Var) this_node) == attr_num) { if (vardots != LispNil) { name_to_look_for = CString(CAR(vardots)); } else { a270 1 /* CDR(i) = CDR(n);*/ a285 4 /* CDR(i) = CDR(n);*/ if (NodeType(CAR(n)) == classTag(Var) && vardots) { set_vardotfields((Var) CAR(n), lispCopy(CDR(vardots))); } a287 1 } @ 2.14 log @fixed some prototype thingies @ text @d2 1 a2 1 * $Header: RCS/RewriteManip.c,v 2.13 91/08/16 03:54:31 glass Exp Locker: glass $ d130 1 a130 1 return lispCons(c,LispNil); @ 2.13 log @fixed bug I created @ text @d2 1 a2 1 * $Header: RCS/RewriteManip.c,v 2.12 91/08/16 03:21:33 glass Exp Locker: glass $ d45 1 a45 1 int this_varno = (int)get_varno ( this_node ); d47 2 a48 2 set_varno ( this_node , new_varno ); CAR(get_varid ( this_node)) = d74 1 a74 1 int this_varno = (int)get_varno ( this_node ); d76 2 a77 2 set_varno (this_node, new_varno); CAR(get_varid ( this_node)) = d143 4 a146 2 set_restype(entry_LHS, get_vartype(entry_RHS)); set_reslen (entry_LHS, get_typlen(get_vartype(entry_RHS))); d163 1 a163 1 if ( get_resno(entry_LHS) == attno ) { d205 1 a205 1 int this_varno = (int)get_varno ( this_node ); d208 1 a208 1 get_varattno(this_node)); d214 1 a214 1 n = (List) make_null(get_vartype(this_node)); d264 1 a264 1 int this_varno = (int)get_varno ( this_node ); d268 1 a268 1 get_varattno(this_node) == attr_num) { d273 2 a274 2 if (get_vartype(this_node) == 32) { /* HACK */ n = (List) make_null(get_vartype(this_node)); d290 1 a290 1 n = (List) make_null(get_vartype(this_node)); d294 1 a294 1 set_vardotfields(CAR(n), lispCopy(CDR(vardots))); d323 1 a323 1 int this_varno = (int)get_varno ( this_node ); d332 1 a332 1 n = (List) make_null(get_vartype(this_node)); @ 2.12 log @fixes postquel function qual problem @ text @d2 1 a2 1 * $Header: RCS/RewriteManip.c,v 2.11 91/08/15 05:46:36 glass Exp Locker: glass $ d259 1 a259 1 modified); @ 2.11 log @fixed bug that caused things after 'replaced' varnodes to be squished. @ text @d2 1 a2 1 * $Header: RCS/RewriteManip.c,v 2.10 91/08/09 00:44:03 glass Exp Locker: glass $ d244 2 a245 1 void HandleRIRAttributeRule(parsetree, rt,tl, rt_index, attr_num,modified) d248 1 a248 1 int rt_index, attr_num,*modified; d276 1 @ 2.10 log @added postquel function support, including infinite nested dots @ text @d2 1 a2 1 * $Header: RCS/RewriteManip.c,v 2.9 91/08/08 18:36:14 glass Exp Locker: glass $ d214 1 a214 1 CDR(i) = CDR(n); d219 1 a219 1 CDR(i) = CDR(n); d273 1 a273 1 CDR(i) = CDR(n); d288 1 a288 1 CDR(i) = CDR(n); d330 1 a330 1 CDR(i) = CDR(n); @ 2.9 log @ partial implementation of postquel functions @ text @d2 1 a2 1 * $Header: RCS/RewriteManip.c,v 2.8 91/08/03 16:49:08 glass Exp Locker: glass $ d119 1 a119 1 static Const make_null(type) d130 1 a130 1 return c; d139 1 a139 1 List entry_RHS = CDR(one_entry); a141 1 Assert(IsA(entry_RHS,Var)); a265 2 elog(DEBUG,"relid = %d, %d", CInteger(getrelid(this_varno,rt)), attr_num); a266 2 if (length(vardots) != 1) elog(WARN, "exceeded nested dot limit"); d269 15 a283 3 else name_to_look_for = (char *) get_attname(CInteger(getrelid(this_varno,rt)), attr_num); d289 3 @ 2.8 log @general cleanup @ text @d2 1 a2 1 * $Header: RCS/RewriteManip.c,v 2.7 91/07/30 07:41:56 glass Exp Locker: glass $ d132 17 d263 2 d269 9 a277 4 n = FindMatchingTLEntry (tl, get_attname(CInteger(getrelid(this_varno,rt)), attr_num)); @ 2.7 log @Note: this code has little to do with the previous version A few support routines from Goh's stuff remain, the rest are new. Unifying theme is parsetree mutilation: RIR varnode manipulation, 'new' processing, some qual stuff, and varno shifting. @ text @d2 1 a2 1 * $Header: RCS/RewriteManip.c,v 2.6 91/03/18 21:00:42 sp Exp $ d138 1 a138 1 List i = NULL; d149 1 a149 1 return ( NULL ); /* could not find a matching RHS */ d156 1 a156 1 List i = NULL; d169 1 a169 1 return ( NULL ); /* could not find a matching RHS */ d172 1 a172 1 ResolveNew(info, targetlist,tree) a219 2 List i; List tl; a220 8 /* are append's expanded yet? */ /* foreach t (targetlist(rule_action)) * if (new.something) (i.e varnode = new) * find something on target list of 'parsetree' * replace new.something with it. */ d228 1 a228 1 HandleRIRAttributeRule(parsetree, rt,tl, rt_index, attr_num,modified) d271 1 a271 1 HandleViewRule(parsetree, rt,tl, rt_index,modified) @ 2.6 log @Now when we process "append" commands that do not specify values for all the attributes of the tuple, we replace all refences to *NEW* with NULL Const nodes (up till now we were replacing them with refernces to *CURRENT* which is not what we want!). @ text @d2 1 a2 1 * $Header: RCS/RewriteManip.c,v 2.5 91/02/26 18:48:27 sp Exp $ d5 4 a8 1 d10 3 d17 3 d21 5 d27 1 d29 1 d59 6 d66 23 a88 11 /* * AddQualifications * - takes a parsetree, and a new qualification * and adds the new qualification onto the parsetree * if the new qual is not null. * * if there is an existing qual, it ands it with the new qual * otherwise, just stick the new qual in * * MODIFIES: parsetree */ d90 2 a91 5 void AddQualifications ( rule_parsetree , new_qual , rule_rtlength) List rule_parsetree; List new_qual; int rule_rtlength; d93 1 a93 2 List copied_qual = NULL ; extern List copy_seq_tree(); d95 1 a95 2 if ( new_qual == NULL ) return; d97 9 a105 10 copied_qual = copy_seq_tree ( new_qual ); OffsetVarNodes ( copied_qual , rule_rtlength ); if ( parse_qualification(rule_parsetree) == NULL ) parse_qualification(rule_parsetree) = copied_qual; else parse_qualification ( rule_parsetree ) = lispCons ( lispInteger(AND), lispCons ( parse_qualification( rule_parsetree), lispCons ( copied_qual, LispNil ))); d107 2 a108 11 /* * FixRangeTable * - remove the first two entries * ( which always correspond to *current* and *new* * and stick on the user rangetable entries after that */ void FixRangeTable ( rule_root , user_rt ) List rule_root; List user_rt; d110 1 a110 1 List rule_rt = root_rangetable(rule_root); d112 1 a112 1 root_rangetable(rule_root) = CDR(CDR(rule_rt)); d114 3 a116 1 CDR(last(rule_rt)) = user_rt; d119 14 a132 7 /* * FindMatchingNew * - given a parsetree, and an attribute number, * find the RHS of a targetlist expression * that matches the attribute we are looking for * returns : matched RHS, or NULL if nothing is found */ d151 4 a154 45 /* * MutateVarNodes * - change varnodes in rule parsetree according to following : * (a) varnos get offset by magnitude "offset" * (b) (varno = 1) => *CURRENT* , set varno to "trigger_varno" * (c) (varno = 2) => *NEW*, replace varnode with matching RHS * of user_tlist, or *CURRENT* or a NULL value * if no such match occurs (see discussion below). * * There is a tricky case here. Sometimes we can not find a match in the * user parsetree for "*NEW*". * This can happen when we have an append or replace command that * does not specify new values for ALL the attributes of the tuple. * * For example if we have a relation "foo(a=int4, b=int4)" * the command "append foo(b=3)" and the command * "replace foo(a=1) where ...." specify new values for only one of * the two attributes of "foo". * * In the case of append we want to replace the reference to the * `NEW' with a null value, i.e. the "append foo(b=3)" * will be equivalent to "append foo(a=, b=3)" * * In case of teh replace however, we want to replace the refernce * to `NEW' with a reference to `CURRENT'. I.e the * command "replace foo(a=1) where ..." is equivalent * to "replace foo(a=1, b=foo.b) where ...." * * Of course one way to do that is to expand the target list of the * user parsetree so that it specifies the correct values for all the * attributes (null in append, the "current" values for replace). * * Another way is to do this substitution on the fly, in this routine. * */ void HandleVarNodes (parse_subtree , user_parsetree , trigger_varno, offset, command) List parse_subtree; List user_parsetree; int trigger_varno; int offset; int command; d157 21 d179 36 a214 15 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 ( parse_targetlist(user_parsetree) , get_varattno ( thisnode )); d216 53 a268 4 if ( matched_new ) { CAR(i) = CAR(matched_new); CDR(i) = CDR(matched_new); break; d270 1 a270 29 /* * No match for 'new' was found. * if this is an APPEND command, substitute * NEW with a null const node. */ if (command == APPEND) { Const c; ObjectId typid; c = RMakeConst(); typid = get_vartype(thisnode); set_consttype(c, typid); set_constlen(c, (Size) get_typlen(typid)); set_constvalue(c, PointerGetDatum(NULL)); set_constisnull(c, true); set_constbyval(c, get_typbyval(typid)); CAR(i) = (List) c; CDR(i) = LispNil; break; } /* * else it is a replace commanf, fall through * to the "CURRENT" case... */ case 1: /* *CURRENT* */ set_varno ( thisnode, trigger_varno ); CAR ( get_varid (thisnode) ) = lispInteger ( trigger_varno ); /* XXX - should fix the varattno too !!! */ d272 5 a276 10 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, command); d281 3 a283 8 /* * take a parsetree and stick on the qual * we assume that the varnos in the qual have * already been appropriately munged */ AddEventQualifications ( parsetree, qual ) List parsetree; List qual; d285 1 d287 11 d299 17 a315 6 if (null(qual)) { /* * a null qual is always true * Do nothing... */ return; d317 1 a318 7 if ( parse_qualification(parsetree) == NULL ) parse_qualification(parsetree) = qual; else parse_qualification ( parsetree ) = lispCons ( lispInteger(AND), lispCons ( parse_qualification( parsetree), lispCons ( qual, LispNil ))); a319 2 } a321 5 /* * take a parsetree and stick on the inverse qual * we assume that the varnos in the qual have * already been appropriately munged */ a322 12 AddNotEventQualifications ( parsetree, qual ) List parsetree; List qual; { if (null(qual)) { /* * A null qual is always true, so its inverse * is always false. * Create a dummy qual which is always false: */ Const c1; a323 14 c1 = RMakeConst(); set_consttype(c1, (ObjectId) 16); /* bool */ set_constlen(c1, (Size) 1); set_constvalue(c1, Int8GetDatum((int8) 0)); /* false */ set_constisnull(c1, false); set_constbyval(c1, true); qual = (List) c1; } AddEventQualifications ( parsetree, lispCons ( lispInteger(NOT), lispCons ( copy_seq_tree (qual), LispNil ))); } @ 2.5 log @'AddEventQualifications' and 'AddNotEventQualificatiions' now work correctly with null event qualifications. @ text @d2 1 a2 1 * $Header: RCS/RewriteManip.c,v 2.4 91/02/24 21:41:42 mao Exp $ d10 1 d12 2 d130 28 a157 1 * of user_tlist, or *CURRENT* if no such match occurs d161 2 a162 1 HandleVarNodes ( parse_subtree , user_parsetree , trigger_varno, offset ) d167 1 d192 23 a214 1 /* if no match, then fall thru to current */ d231 1 a231 1 trigger_varno,offset); a284 1 Const RMakeConst(); @ 2.4 log @get rid of debugging messages @ text @d2 1 a2 1 * $Header: RCS/RewriteManip.c,v 2.3 91/02/02 15:03:29 sp Exp Locker: mao $ d193 8 a222 1 Assert ( qual != NULL ); d224 17 @ 2.3 log @Added a 'Header:' line so that 'rcsnew -na' will not complain. @ text @d2 1 a2 1 * $Header: $ a162 1 printf("replacing *CURRENT* or unmatch *NEW*"); @ 2.2 log @fixes problems with event qualifications @ text @d1 5 @ 2.1 log @stable version ; everything except ev_quals @ text @d177 42 @ 1.2 log @should modify copied qual, not new qual @ text @@ 1.1 log @Initial revision @ text @d6 1 a6 1 static void d55 1 d60 1 a60 1 copied_qual = new_qual; /* XXX - should change to lispCopy ??? */ d62 1 a62 1 OffsetVarNodes ( new_qual , rule_rtlength ); @