head 1.12; access; symbols Version_2_1:1.10; locks; strict; comment @ * @; 1.12 date 91.11.18.17.29.14; author mer; state Exp; branches; next 1.11; 1.11 date 91.03.18.18.44.48; author sp; state Exp; branches; next 1.10; 1.10 date 91.02.02.15.17.28; author sp; state Exp; branches; next 1.9; 1.9 date 90.12.10.20.56.15; author ong; state Exp; branches; next 1.8; 1.8 date 90.11.01.09.33.40; author ong; state Exp; branches; next 1.7; 1.7 date 90.10.26.11.51.47; author ong; state Exp; branches; next 1.6; 1.6 date 90.10.22.11.28.45; author ong; state Exp; branches; next 1.5; 1.5 date 90.10.18.09.23.06; author ong; state Exp; branches; next 1.4; 1.4 date 90.10.16.12.40.08; author ong; state Exp; branches; next 1.3; 1.3 date 90.10.16.09.06.38; author ong; state Exp; branches; next 1.2; 1.2 date 90.10.12.10.34.58; author ong; state Exp; branches; next 1.1; 1.1 date 90.10.09.11.50.19; author ong; state Exp; branches; next ; desc @routines to handleunion queries pertaining to versions. lp @ 1.12 log @prototype changes (the last?) @ text @/* * Routine takes the 'union' parsetree, messes around with it, * strips the union relations, and returns * a list of orthogonal plans. * * NOTE: Current implementation of versions disallows schema changes * between versions. Thus we may assume that the attributes * remain the same between versions and their deltas. * * $Header: /users/mer/postgres/src/planner/prep/RCS/handleunion.c,v 1.11 1991/03/18 18:44:48 sp Exp mer $ */ #include "tmp/c.h" #include "nodes/nodes.h" #include "nodes/pg_lisp.h" #include "nodes/execnodes.h" #include "nodes/plannodes.h" #include "nodes/plannodes.a.h" #include "nodes/primnodes.h" #include "nodes/primnodes.a.h" #include "nodes/relation.h" #include "nodes/relation.a.h" #include "parser/parse.h" #include "parser/parsetree.h" #include "tmp/utilities.h" #include "utils/log.h" #include "utils/lsyscache.h" #include "planner/internal.h" #include "planner/plancat.h" #include "planner/planner.h" #include "planner/prepunion.h" #include "planner/clauses.h" #include "planner/handleunion.h" #include "planner/semanopt.h" /* #include "planner/cfi.h" */ /* #define LispRemove remove */ List handleunion (root,rangetable, tlist, qual) List root, rangetable, tlist, qual; { List new_root = LispNil; List temp_tlist = LispNil; List temp_qual = LispNil; List i = LispNil; List tlist_qual = LispNil; List rt_entry = LispNil; List temp = LispNil; List new_parsetree = LispNil; List union_plans = LispNil; int planno = 0; List tmp_uplans = LispNil; List firstplan = LispNil; List secondplan = LispNil; int num_plans = 0; /* * SplitTlistQual returns a list of the form: * ((tlist1 qual1) (tlist2 qual2) ...) */ /* * First remove the union flag from the rangetable entries * since we are processing them now. */ foreach(i,rangetable) { rt_entry = CAR(i); if (member(lispAtom("union"),rt_flags(rt_entry))) { rt_flags(rt_entry) = LispRemove(lispAtom("union"), rt_flags(rt_entry)); } } tlist_qual = SplitTlistQual (root,rangetable,tlist,qual); #ifdef VERBOSE num_plans = length(tlist_qual); printf("####################\n"); printf("number of plans generated: %d\n", num_plans); printf("####################\n"); #endif foreach (i, tlist_qual) { temp = CAR(i); new_parsetree = lispCons(root,lispCons(CAR(temp), lispCons(CADR(temp), LispNil) )); union_plans = nappend1(union_plans, (LispValue)planner(new_parsetree)); } /* * testing: */ /* union_plans = CDR(union_plans); */ #ifdef SWAP_PLANS firstplan = CAR(union_plans); secondplan = CADR(union_plans); CAR(union_plans) = secondplan; CADR(union_plans) = firstplan; #endif /* foreach(i, union_plans) { planno += 1; tmp_uplans = nappend1(tmp_uplans, CAR(i)); } */ return(union_plans); } /* * Given a 'union'ed tlist and qual, this routine splits them * up into separate othrogonal (tlist qual) pairs. * For example, * tlist: (emp | emp1).name * qual: (emp | emp1). salary < 5000 * will be split into: * ( ((emp.name) (emp.salary < 5000)) ((emp1.name) (emp1.salary < 5000)) ) */ List SplitTlistQual(root,rangetable,tlist, qual) List root,rangetable,tlist, qual; { List i = LispNil; List tqlist = LispNil; List temp = LispNil; List tl_list = LispNil; List qual_list = LispNil; List unionlist = LispNil; List mod_qual = LispNil; List varlist = LispNil; List is_redundent = LispNil; unionlist = collect_union_sets(tlist,qual); #ifdef VERBOSE printf("##########################\n"); printf("Union sets are: \n"); lispDisplay(unionlist,0); printf("\n"); fflush(stdout); printf("##########################\n"); #endif /* * If query is a delete, the tlist is null. */ if (CAtom(root_command_type_atom(root)) == DELETE) foreach(i,unionlist) foreach(temp,CAR(i)) tl_list = nappend1(tl_list, LispNil); else { tl_list = lispCons(tlist, LispNil); foreach(i, unionlist) /* This loop effectively handles union joins */ tl_list = SplitTlist(CAR(i),tl_list); } qual_list = lispCons(qual,LispNil); foreach(i,unionlist) { qual_list = SplitQual(CAR(i),qual_list); } /* * The assumption here is that both the tl_list and the qual_list, * must be of the same length, if not, something funky has happened. * * XXX I think this is not true in the case of 'DELETEs' ! sp. * XXX In this case, 'tl_list' is nil. */ if (CAtom(root_command_type_atom(root)) != DELETE) if (length (tl_list) != length(qual_list)) elog (WARN, "UNION: tlist with missing qual, or vice versa"); if(null(tl_list)) { /* * this is a special case, where tl_list is null (i.e. this * is a DELETE command. * DISCLAIMER: I don't know what this code is doing, I don't * know what it is supposed to do, all I know is that before it * didn't work in queries like: * "delete foobar from f in (foo | bar) where foobar.a = 1" * and now it works (provided that you made a couple of prayers * and/or sacrifices to the gods....). * sp._ */ temp = NULL; varlist = find_allvars(root,rangetable, temp, CAR(qual_list)); is_redundent = LispNil; mod_qual = SemantOpt(varlist,rangetable,CAR(qual_list),&is_redundent,1); if (is_redundent != LispTrue) { mod_qual = SemantOpt2(rangetable,mod_qual,mod_qual,temp); tqlist = nappend1(tqlist, lispCons(temp, lispCons(mod_qual, LispNil))); } qual_list = CDR(qual_list); } else { foreach(i, tl_list) { temp = CAR(i); /* * Varlist contains the list of varnos of relations that participate * in the current query. It is used to detect existential clauses. * Initially, varlist contains the list of target relations (varnos). * This should only be done once for each query. */ varlist = find_allvars(root,rangetable, temp, CAR(qual_list)); is_redundent = LispNil; mod_qual = SemantOpt(varlist,rangetable,CAR(qual_list),&is_redundent,1); if (is_redundent != LispTrue) { mod_qual = SemantOpt2(rangetable,mod_qual,mod_qual,temp); tqlist = nappend1(tqlist, lispCons(temp, lispCons(mod_qual, LispNil))); } qual_list = CDR(qual_list); } } return (tqlist); } /* * SplitTlist * returns a list of the form (tlist1 tlist2 ...) */ List SplitTlist (unionlist,tlists) List unionlist; List tlists; { List i = LispNil; List j = LispNil; List x = LispNil; List tlist = LispNil; List t = LispNil; List varnum = LispNil; List new_tlist ; List tle = LispNil; List varlist = LispNil; Var varnode = (Var)NULL; List tl_list = LispNil; List flatten_list = LispNil; foreach(t, tlists) { tlist = CAR(t); foreach (i, unionlist) { varnum = CAR(i); new_tlist = LispNil; new_tlist = copy_seq_tree(tlist); foreach (x, new_tlist) { tle = CAR(x); varlist = tl_expr(tle); if (IsA(varlist,Const) || IsA(varlist,Var)) flatten_list = LispNil; else if (is_clause(varlist)) split_tlexpr(CDR(varlist),varnum); else if (CAtom(CAR(varlist)) == UNION) { flatten_list = flatten_union_list(CDR(varlist)); foreach (j, flatten_list) { varnode = (Var)CAR(j); /* * Find matching entry, and change the tlist to it. */ if (CInteger(varnum) == get_varno(varnode)) { tl_expr(tle) = (List)varnode; break; } } } /* for, varlist */ } /* for, new_tlist*/ /* * At this point, the new_tlist is an orthogonal targetlist, without * any union relations. */ if (new_tlist == NULL) elog(WARN, "UNION: resulting tlist is empty"); tl_list = nappend1(tl_list,new_tlist); } } /*tlists */ return(tl_list); } /* * This routine is called to split the tlist whenever * there is an expression in the targetlist. * Routine returns nothing as it modifies the tlist in place. */ void split_tlexpr(clauses,varnum) List clauses; List varnum; { List x = LispNil; List ulist = LispNil; List clause = LispNil; List flat_list = LispNil; Var varnode = (Var)NULL; List i = LispNil; foreach (x,clauses) { clause = CAR(x); if (IsA(clause,Const) || IsA(clause,Var) ) flat_list = LispNil; else if (is_clause(clause)) split_tlexpr(CDR(clause), varnum); else if (consp(clause) && CAtom(CAR(clause)) == UNION) { flat_list = flatten_union_list(CDR(clause)); foreach(i,flat_list) { varnode = (Var)CAR(i); if (CInteger(varnum) == get_varno(varnode)) { CAR(clause) = (List)varnode; break; } } } } } /* * collect_union_sets * runs through the tlist and qual, and forms a list of * unions sets in the query. * If there is > 1 union set, we are dealing with a union join. */ List collect_union_sets(tlist,qual) List tlist; List qual; { List i = LispNil; List x = LispNil; List j = LispNil; int varno = 0; List tle = LispNil; List varlist = LispNil; List current_union_set = LispNil; List union_sets = LispNil; List qual_union_sets = LispNil; List flattened_ulist = LispNil; /* * First we run through the targetlist and collect all union sets * there. */ foreach(i, tlist) { tle = CAR(i); varlist = tl_expr(tle); current_union_set = LispNil; if (is_clause(varlist)) { /* if it is an expression */ flattened_ulist = collect_tlist_uset(CDR(varlist)); foreach (x, flattened_ulist) current_union_set = nappend1(current_union_set, lispInteger(get_varno((Var)CAR(x))) ); } else if (consp(varlist) && CAtom(CAR(varlist)) == UNION) { flattened_ulist = flatten_union_list(CDR(varlist)); foreach (x, flattened_ulist) current_union_set = nappend1(current_union_set, lispInteger(get_varno((Var)CAR(x))) ); } union_sets = nappend1(union_sets, current_union_set); } union_sets = remove_subsets(union_sets); /* * Now we run through the qualifications to collect * union sets. */ qual_union_sets = find_qual_union_sets(qual); if (qual_union_sets != LispNil) foreach(i, qual_union_sets) union_sets = nappend1(union_sets, CAR(i)); if (length(union_sets) > 1) union_sets = remove_subsets(union_sets); return(union_sets); } /* * This routine is called whenever there is a * an expression in the targetlist. * Returns a flattened ulist if found. */ List collect_tlist_uset(args) List args; { List retlist = LispNil; List x = LispNil; List i = LispNil; List current_clause = LispNil; List ulist = LispNil; foreach (x, args) { current_clause = CAR(x); if (IsA(current_clause,Const)) retlist = LispNil; else if (is_clause(current_clause)) retlist = collect_tlist_uset(CDR(current_clause)); else if (consp(current_clause) && CAtom(CAR(current_clause)) == UNION) { retlist = flatten_union_list(CDR(current_clause)); } else retlist = LispNil; /* If it is just a varnode. */ foreach(i,retlist) if (CAR(i) != LispNil) ulist = nappend1(ulist,CAR(i)); } return(ulist); } List find_qual_union_sets(qual) List qual; { List leftop = LispNil; List rightop = LispNil; List i = LispNil; List j = LispNil; List union_sets = LispNil; List current_union_set = LispNil; List qual_uset = LispNil; List flattened_ulist = LispNil; if (null(qual)) return(LispNil); else if (is_clause(qual)) { leftop = (List) get_leftop(qual); rightop = (List) get_rightop(qual); if (consp(leftop) && CAtom(CAR(leftop)) == UNION) { current_union_set = LispNil; flattened_ulist = flatten_union_list(CDR(leftop)); foreach(i, flattened_ulist) current_union_set = nappend1(current_union_set, lispInteger(get_varno((Var)CAR(i))) ); union_sets = nappend1(union_sets, current_union_set); } if (consp(rightop) && CAtom(CAR(rightop)) == UNION) { current_union_set = LispNil; flattened_ulist = flatten_union_list(CDR(rightop)); foreach(i, flattened_ulist) current_union_set = nappend1(current_union_set, lispInteger(get_varno((Var)CAR(i))) ); union_sets = nappend1(union_sets, current_union_set); } } else if (and_clause(qual)) { foreach(j,get_andclauseargs(qual)) { qual_uset = find_qual_union_sets(CAR(j)); if (qual_uset != LispNil) foreach(i,qual_uset) union_sets = nappend1(union_sets, CAR(i)); } } else if (or_clause(qual)) { foreach(j,get_orclauseargs(qual)) { qual_uset = find_qual_union_sets(CAR(j)); if (qual_uset != LispNil) foreach(i,qual_uset) union_sets = nappend1(union_sets, CAR(i)); } } else if (not_clause(qual)) { qual_uset = find_qual_union_sets(CDR(qual)); if (qual_uset != LispNil) foreach(i,qual_uset) union_sets = nappend1(union_sets, CAR(i)); } return(union_sets); } List flatten_union_list(ulist) List ulist; { List retlist = LispNil; List i = LispNil; List tmp_var = LispNil; List tmplist = LispNil; foreach(i,ulist) { tmp_var = CAR(i); if (consp(tmp_var) && CAtom(CAR(tmp_var)) == UNION) tmplist = flatten_union_list(CDR(tmp_var)); else retlist = nappend1(retlist, tmp_var); } if (tmplist) foreach(i, tmplist) retlist= nappend1(retlist, CAR(i)); return(retlist); } /* * remove_subsets * Routine finds and removes any subsets in the given list. * Returns the modified list. * Thus given ( (A B C) (B C) (D E F) (D F) ), routine returns: * ( (A B C) (D E F) ) */ List remove_subsets(usets) List usets; { List retlist = LispNil; List i = LispNil; List j = LispNil; List k = LispNil; List uset1 = LispNil; List uset2 = LispNil; int is_subset = 1; foreach(i, usets) { uset1 = CAR(i); foreach(j, CDR(i)) { uset2 = CAR(j); if (uset2 == LispNil) break; if (length (uset1) >= length(uset2) && length(uset2) != 1) { foreach(k, uset2) if (!member(CAR(k),uset1)) { is_subset = 0; break; } if (is_subset) CAR(j) = lispCons(lispInteger(1), LispNil); } /* uset1 > uset2 */ else if (length(uset1) < length(uset2) && length(uset1) != 1) { foreach(k,uset1) if (!member(CAR(k), uset2)) { is_subset = 0; break; } if (is_subset) CAR(i)= lispCons(lispInteger(1),LispNil); } is_subset = 1; } /* inner loop usets */ } /* outer loop usets */ foreach (i, usets) if (length (CAR(i)) > 1) retlist = nappend1(retlist, CAR(i) ); return(retlist); } /* * SplitQual: * * Given a list of union rels, this routine splits the qualification * up accordingly. * NOTE: Only union rels in the qualification will be split. * ( I believe that utimately, we want to split union rels by position. ) * * Input: (uvar1 uvar2 ...) (unioned qual) * Output: (qual1 qual2 ...) */ List SplitQual (ulist, uquals) List ulist; List uquals; { List i = LispNil; List x = LispNil; List uqual = LispNil; List uvarno = LispNil; List qual_list = LispNil; List currentlist = LispNil; List new_qual = LispNil; foreach(x, uquals) { uqual = CAR(x); if (uqual == LispNil) { foreach(i, ulist) qual_list = nappend1(qual_list, LispNil); return(qual_list); } foreach(i, ulist) { uvarno = CAR(i); currentlist = nappend1(currentlist, uvarno); new_qual = copy_seq_tree(uqual); new_qual = find_matching_union_qual(currentlist, new_qual); qual_list = nappend1(qual_list, new_qual); currentlist = LispNil; } } return(qual_list); } /* * find_matching_union_qual * * Given a union qual, and a union relation, returns * the qualifications that apply to it. */ List find_matching_union_qual(ulist, qual) List ulist, qual; { List leftop = LispNil; List rightop = LispNil; List op = LispNil; List matching_clauseargs = LispNil; List retqual = LispNil; List i = LispNil; List tmp_list = LispNil; if (null(qual)) return(LispNil); else if (is_clause(qual)) { leftop = (List)get_leftop(qual); rightop = (List)get_rightop(qual); op = get_op(qual); leftop = find_matching_union_qual(ulist,leftop); rightop = find_matching_union_qual(ulist,rightop); match_union_clause(ulist, &leftop, &rightop); retqual = make_opclause((Oper)op,(Var)leftop,(Var)rightop); /* * if the clause does not belong to the current union relation, * remove it from the qualification. */ /* if (matching_clauseargs == LispNil) remove(clause, clauses); * NOTE: may have to mod. qual * else clauseargs = matching_clauseargs; */ } else if (and_clause (qual)) { foreach(i, get_andclauseargs(qual)) { tmp_list = nappend1(tmp_list, find_matching_union_qual(ulist, CAR(i))); } retqual = make_andclause(tmp_list); } else if (or_clause (qual)) { foreach(i, get_orclauseargs(qual)) { tmp_list = nappend1(tmp_list, find_matching_union_qual(ulist, CAR(i))); } retqual = make_orclause(tmp_list); } else if (not_clause (qual)) { retqual = find_matching_union_qual(ulist, get_notclausearg(qual)); retqual = make_notclause(retqual); } else retqual = qual; return(retqual); } /* * match_union_clauses: * * Given a list of *2* clause args, (leftarg rightarg), * it picks out the clauses within unions that * are relevant to the particular union relation being scanned. * * returns nothing. It modifies the qual in place. */ void match_union_clause (unionlist, leftarg, rightarg) List unionlist, *leftarg, *rightarg; { List i = LispNil; List x = LispNil; List varlist = LispNil; Var uvarnode = (Var)NULL; List varlist2 = LispNil; /* * If leftarg is a union var. */ if (consp(*leftarg) && CAtom(CAR(*leftarg)) == UNION) { varlist = flatten_union_list(CDR(*leftarg)); /* varlist = CDR(*leftarg); */ foreach(i,varlist) { uvarnode = (Var)CAR(i); if (member(lispInteger(get_varno(uvarnode)), unionlist)) { *leftarg = (List)uvarnode; break; } } } /* * If rightarg is a union var. */ if (consp(*rightarg) && CAtom(CAR(*rightarg)) == UNION) { varlist = flatten_union_list(CDR(*rightarg)); /* varlist = CDR(*rightarg); */ foreach(i,varlist) { uvarnode = (Var)CAR(i); if (member(lispInteger(get_varno(uvarnode)), unionlist)) { *rightarg = (List)uvarnode; break; } } } } #ifdef NOT_USED /* * Routine is not used. * find_union_vars * runs through the rangetable, and forms a list of all the * relations that are unioned. It will also remove the union * flag from the rangetable entries after it is done processing * them. * REturns a list of varnos. */ List find_union_vars (rangetable) List rangetable; { List i = LispNil; List unionlist = LispNil; List rt_entry = LispNil; Index uvarno = 0; /* * XXX what about the case when there are 2 emps in the rangetable, and * both are union relations? * Currently, both would appear in the unionlist. */ foreach( i, rangetable) { rt_entry = CAR(i); uvarno += 1; if (member(lispAtom("union"),rt_flags(rt_entry))) { unionlist = nappend1(unionlist, lispInteger(uvarno)); rt_flags(rt_entry) = LispRemove(lispAtom("union"), rt_flags(rt_entry)); } } return(unionlist); } #endif @ 1.11 log @bug fix that made delete union queries to die a horrible death... @ text @d10 1 a10 1 * $Header: RCS/handleunion.c,v 1.10 91/02/02 15:17:28 sp Exp $ d95 1 a95 1 planner(new_parsetree)); d338 1 a338 1 split_tlexpr(CDR(clause)); d391 1 a391 1 lispInteger(get_varno(CAR(x))) ); d398 1 a398 1 lispInteger(get_varno(CAR(x))) ); d486 1 a486 1 lispInteger(get_varno(CAR(i))) ); d495 1 a495 1 lispInteger(get_varno(CAR(i))) ); d690 1 a690 1 retqual = make_opclause(op,leftop,rightop); @ 1.10 log @added 'Header' line so that 'rcsnew -na' does not complain. @ text @d10 1 a10 1 * $Header: $ d178 3 d183 3 a185 2 if (length (tl_list) != length(qual_list)) elog (WARN, "UNION: tlist with missing qual, or vice versa"); d187 27 a213 2 foreach(i, tl_list) { temp = CAR(i); d215 6 a220 6 /* * Varlist contains the list of varnos of relations that participate * in the current query. It is used to detect existential clauses. * Initially, varlist contains the list of target relations (varnos). * This should only be done once for each query. */ d222 12 a233 9 varlist = find_allvars(root,rangetable, temp, CAR(qual_list)); is_redundent = LispNil; mod_qual = SemantOpt(varlist,rangetable,CAR(qual_list),&is_redundent,1); if (is_redundent != LispTrue) { mod_qual = SemantOpt2(rangetable,mod_qual,mod_qual,temp); tqlist = nappend1(tqlist, lispCons(temp, lispCons(mod_qual, LispNil))); a234 2 qual_list = CDR(qual_list); } @ 1.9 log @added second level of semant. opt @ text @d10 1 a10 1 * $Header: @ 1.8 log @added semant. opt to eliminate redundent queries. @ text @d40 1 a40 1 /*#define LispRemove remove */ d196 2 a197 1 if (is_redundent != LispTrue) d202 2 a203 1 qual_list = CDR(qual_list); d245 2 a246 1 if (IsA(varlist,Const) || IsA(varlist,Var)) ; d248 15 a262 15 if (CAtom(CAR(varlist)) == UNION) { flatten_list = flatten_union_list(CDR(varlist)); foreach (j, flatten_list) { varnode = (Var)CAR(j); /* * Find matching entry, and change the tlist to it. * * NOTE: Also need to handle the case when a particular * rel. is not found in the union. In that case, * we should remove the tle (i.e, (resdom var) pair). * HOWEVER, this is not done just yet. */ if (CInteger(varnum) == get_varno(varnode)) { tl_expr(tle) = (List)varnode; break; d265 1 a265 1 } d267 1 a267 1 d284 41 d356 3 a358 3 if (consp(varlist) && CAtom(CAR(varlist)) == UNION) { flattened_ulist = flatten_union_list(CDR(varlist)); d362 7 d370 1 a370 1 } d394 37 @ 1.7 log @fixed up a bunch a stuff to allow version to work correctly. @ text @d40 1 a40 1 /* #define LispRemove remove */ d82 1 d87 1 d147 1 d150 1 a150 1 d157 1 a157 1 d194 7 a200 5 mod_qual = SemantOpt(varlist,rangetable,CAR(qual_list)); tqlist = nappend1(tqlist, lispCons(temp, lispCons(mod_qual, LispNil))); d204 1 a204 1 return (tqlist); a434 97 } /* * find_union_sets * runs through the rangetable, and forms a list of all union * sets. Routine removes the union flag from the rte after * it is done processing . * If there is > 1 union set, we are dealing with a union join. */ List find_union_sets(rangetable) List rangetable; { List i = LispNil; List x = LispNil; List j = LispNil; int varno = 0; List rt_entry = LispNil; List rt_vars = LispNil; List retlist = LispNil; List ulist = LispNil; List u_set = LispNil; List vlist = LispNil; List varname = LispNil; int In_List; int position; foreach(i,rangetable) { rt_entry = CAR(i); varno += 1; if (member(lispAtom("union"),rt_flags(rt_entry))) { rt_flags(rt_entry) = LispRemove(lispAtom("union"), rt_flags(rt_entry)); } rt_vars = CAR(rt_entry); if (consp(rt_vars)) { foreach(x,rt_vars) { varname = CAR(x); In_List = 0; position = 0; if (ulist == LispNil) { ulist = nappend1(ulist, lispCons(varname, LispNil)); vlist = nappend1(vlist, lispCons(lispInteger(varno), LispNil)); In_List = 1; } else foreach(j,ulist) { if (member(varname, CAR(j))) { u_set = nth(position,vlist); if (!member(lispInteger(varno), u_set)) u_set = nappend1(u_set,lispInteger(varno)); In_List = 1; break; } position += 1; } if (!In_List) { ulist = nappend1(ulist, lispCons(varname, LispNil)); vlist = nappend1(vlist,lispCons(lispInteger(varno), LispNil)); } } /* rt_vars */ } else { /* If it is a single var. */ varname = rt_vars; In_List = 0; position = 0; if (ulist == LispNil) { ulist = nappend1(ulist, lispCons(varname, LispNil)); vlist = nappend1(vlist, lispCons(lispInteger(varno), LispNil)); In_List = 1; } else foreach(j,ulist) { if (member(varname, CAR(j))) { u_set = nth(position,vlist); if (!member(lispInteger(varno), u_set)) u_set = nappend1(u_set,lispInteger(varno)); In_List = 1; break; } position += 1; } /* ulist */ if (!In_List) { ulist = nappend1(ulist, lispCons(varname, LispNil)); vlist = nappend1(vlist,lispCons(lispInteger(varno), LispNil)); } } } /* rangetable */ foreach(i,vlist) { if (length(CAR(i)) > 1) { /* i.e a union set */ retlist = nappend1 (retlist, CAR(i)); } } retlist = remove_subsets(retlist); return(retlist); @ 1.6 log @bug fix for semant. opt of unions @ text @d40 1 a40 1 /*#define LispRemove remove */ d60 1 d67 13 d82 5 d146 1 a146 1 unionlist = find_union_sets(rangetable); d148 7 d226 1 d241 2 a242 1 foreach (j, CDR(varlist)) { d275 6 d282 16 d299 133 d551 1 a551 1 foreach(j, CDR(usets)) { a555 1 /* Here, assume that there are no duplicate sets. */ d557 1 a557 1 if (length (uset1) > length(uset2) && a574 1 d578 1 d729 2 a730 1 varlist = CDR(*leftarg); d744 2 a745 1 varlist = CDR(*rightarg); @ 1.5 log @removed routine that had a "remove" in it @ text @d40 2 d125 1 d138 1 a138 1 foreach(i, unionlist) d156 10 a165 1 mod_qual = SemantOpt(root,rangetable,temp,CAR(qual_list)); d253 1 @ 1.4 log @changed remove() to LispRemove() for Posix compatibility. @ text @d265 1 a265 1 rt_flags(rt_entry) = remove(lispAtom("union"), a395 63 * Routine is not used. * find_union_vars * runs through the rangetable, and forms a list of all the * relations that are unioned. It will also remove the union * flag from the rangetable entries after it is done processing * them. * REturns a list of varnos. */ List find_union_vars (rangetable) List rangetable; { List i = LispNil; List unionlist = LispNil; List rt_entry = LispNil; Index uvarno = 0; /* * XXX what about the case when there are 2 emps in the rangetable, and * both are union relations? * Currently, both would appear in the unionlist. */ foreach( i, rangetable) { rt_entry = CAR(i); uvarno += 1; if (member(lispAtom("union"),rt_flags(rt_entry))) { unionlist = nappend1(unionlist, lispInteger(uvarno)); rt_flags(rt_entry) = LispRemove(lispAtom("union"), rt_flags(rt_entry)); } } return(unionlist); } /* List tle = LispNil; List expr = LispNil; List x = LispNil; List varlist = LispNil; Var unionvar = (Var)NULL; foreach (i,tlist) { tle = CAR(i); expr = tl_expr(tle); if (CAtom(CAR(expr)) == UNION ) { varlist = CDR(expr); foreach (x, varlist) { unionvar = (Var)CAR(x); uvarno = get_varno(unionvar); if (!(member(lispInteger(uvarno), unionlist))) unionlist = nappend1(unionlist, lispInteger(uvarno)); } } } */ /* d559 39 @ 1.3 log @fix for version joins. @ text @d426 1 a426 1 rt_flags(rt_entry) = remove(lispAtom("union"), @ 1.2 log @now handles union sets properly, and understands union joins. @ text @d20 2 d55 3 d80 1 a80 1 /* union_plans = CDR(union_plans); */ d82 3 d86 10 d240 1 a240 1 * it is done processing . a259 1 d264 1 a264 1 if (member(lispAtom("union"),rt_flags(rt_entry))) d267 1 a285 1 position += 1; d289 1 d329 1 d334 63 @ 1.1 log @Initial revision @ text @d52 1 d70 4 d75 3 d106 2 a107 1 unionlist = find_union_vars(rangetable); d113 11 a123 3 tl_list = nappend1(tl_list, LispNil); else tl_list = SplitTlist(unionlist,tlist); a124 2 qual_list = SplitQual(unionlist,qual); d129 1 a129 1 d155 1 a155 1 SplitTlist (unionlist,tlist) d157 1 a157 1 List tlist; d162 2 d171 6 a176 4 foreach (i, unionlist) { varnum = CAR(i); new_tlist = LispNil; new_tlist = copy_seq_tree(tlist); d178 23 a200 23 foreach (x, new_tlist) { tle = CAR(x); varlist = tl_expr(tle); if (IsA(varlist,Const) || IsA(varlist,Var)) ; else if (CAtom(CAR(varlist)) == UNION) { foreach (j, CDR(varlist)) { varnode = (Var)CAR(j); /* * Find matching entry, and change the tlist to it. * * NOTE: Also need to handle the case when a particular * rel. is not found in the union. In that case, * we should remove the tle (i.e, (resdom var) pair). * HOWEVER, this is not done just yet. */ if (CInteger(varnum) == get_varno(varnode)) { tl_expr(tle) = (List)varnode; break; } } /* for, varlist */ } } /* for, new_tlist*/ d202 4 a205 4 /* * At this point, the new_tlist is an orthogonal targetlist, without * any union relations. */ d207 2 a208 2 if (new_tlist == NULL) elog(WARN, "UNION: resulting tlist is empty"); d210 3 a212 2 tl_list = nappend1(tl_list,new_tlist); } d229 14 d244 68 d313 1 d389 1 a389 1 SplitQual (ulist, uqual) d391 1 a391 1 List uqual; d394 2 d401 15 a415 4 if (uqual == LispNil) { foreach(i, ulist) qual_list = nappend1(qual_list, LispNil); return(qual_list); d417 1 a417 10 foreach(i, ulist) { uvarno = CAR(i); currentlist = nappend1(currentlist, uvarno); new_qual = copy_seq_tree(uqual); new_qual = find_matching_union_qual(currentlist, new_qual); qual_list = nappend1(qual_list, new_qual); currentlist = LispNil; } return(qual_list); d458 1 a458 1 if (matching_clauseargs == LispNil) d506 1 d516 5 a520 9 /* (Op (uvar) Const) */ if (IsA(*rightarg,Const)) { foreach (i, varlist) { uvarnode = (Var)CAR(i); if (member(lispInteger(get_varno(uvarnode)), unionlist)) { *leftarg = (List)uvarnode; break; } d522 13 a534 9 } /* Const */ /* (Op (uvar) var) */ else if (IsA(*rightarg,Var)) { foreach (i, varlist) { uvarnode = (Var)CAR(i); if (member(lispInteger(get_varno(uvarnode)), unionlist)) { *leftarg = (List)uvarnode; break; } a535 25 } /* Var */ /* * (Op (uvar1) (uvar2) ) * This gets real hairy. * * If we ever get here, we have a union join. * In this case, we need to have a ulist for each set * of union joins. * Eg: * retrieve (A | B).all where (A | B).foo = (B | C).bar * and (B | A). bla = const * the 2 ulists are: (a b) and (b c), and the union join query * will be split into * retrieve (A.all) where A.foo = B.bar and B.bla = const * and * retrieve (B.all) where B.foo = C.bar and A.bla = const * * XXX sounds problematic. * Supported. */ else if (consp(*rightarg)) { if (CAtom(CAR(*rightarg)) == UNION) { varlist2 = CDR(*rightarg); } d537 1 a537 1 } /* UNION */ @