KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > xquark > extractor > algebra > RemoveIntermediateProjectVisitor


1 /*
2  * This file belongs to the XQuark distribution.
3  * Copyright (C) 2003 Universite de Versailles Saint-Quentin.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307.
18  * You can also get it at http://www.gnu.org/licenses/lgpl.html
19  *
20  * For more information on this software, see http://www.xquark.org.
21  */

22
23 package org.xquark.extractor.algebra;
24
25 import java.util.*;
26
27 import org.xquark.extractor.common.Debug;
28 import org.xquark.extractor.common.SqlWrapperException;
29 import org.xquark.xquery.parser.XQueryExpression;
30
31 /**
32  * This visitor seems to clean useless projection and rename nodes that are
33  * systematically generated from Qdb.
34  * TODO: check the precise behavior.
35  */

36 public final class RemoveIntermediateProjectVisitor extends DefaultCompleteVisitor {
37     private static final String JavaDoc RCSRevision = "$Revision: 1.7 $";
38     private static final String JavaDoc RCSName = "$Name: $";
39
40     private TopDownReplacer _topDownReplacer;
41     private ReplaceTractor _replaceTractor;
42
43     private Stack _scopeStack = new Stack();
44
45     private RemoveProjectVoteVisitor _voteVisitor = new RemoveProjectVoteVisitor();
46
47     public void reinit() {
48         _scopeStack.clear();
49         _voteVisitor.reinit();
50         createScope();
51     }
52
53     public RemoveIntermediateProjectVisitor() {
54     }
55
56     public TopDownReplacer getReplacerInstance() {
57         if (null == _topDownReplacer) {
58             _topDownReplacer = new TopDownReplacer();
59         }
60         return _topDownReplacer;
61     }
62
63     public ReplaceTractor getTractorInstance() {
64         if (null == _replaceTractor) {
65             _replaceTractor = new ReplaceTractor();
66         }
67         return _replaceTractor;
68     }
69
70     private boolean isDeletePermitted() {
71         // Trace.enter(this, "isDeletePermitted()");
72
boolean retVal = ((Scope) _scopeStack.peek())._deletePermited;
73         // Trace.exit(this, "isDeletePermitted()", retVal.toString());
74
return retVal;
75     }
76
77     private void permitDelete(Expression node, boolean permit) {
78         //Trace.enter(this, "permitDelete(boolean permit)", node.toString() + "\t" + (permit ? "true" : "false"));
79
Scope currentScope = (Scope) _scopeStack.peek();
80         currentScope._deletePermited = permit;
81         currentScope._node = node;
82         //Trace.exit(this, "permitDelete(boolean permit)", node.toString() + "\t" + (permit ? "true" : "false"));
83
}
84
85     private Expression currentPermiter() {
86         //Trace.enter(this, "currentPermiter()");
87
Scope currentScope = (Scope) _scopeStack.peek();
88         Debug.assertTrue(currentScope._deletePermited, "currentScope._deletePermited");
89         //Trace.exit(this, "currentPermiter()");
90
return currentScope._node;
91     }
92
93     private void createScope() {
94         _scopeStack.push(new Scope());
95     }
96
97     private Scope currentScope() {
98         return (Scope) _scopeStack.peek();
99     }
100
101     private void leaveScope() {
102         //Trace.enter(this, "leaveScope()");
103
RenameRelation rr = currentScope()._unresolvedRenameRelation;
104         if (null != rr)
105             removeUnresolvedRename(rr);
106
107         _scopeStack.pop();
108         //Trace.exit(this, "leaveScope()");
109
}
110
111     private void removeUnresolvedRename(RenameRelation rr) {
112         if (null != rr.getFather() && !(rr.getOperand() instanceof Table)) {
113             /* remove this RenameRelation*/
114             //Trace.message(this, "leaveScope()", "Removing unresolved RenameRelation...");
115
/* make up map*/
116             HashMap map = new HashMap();
117             Object JavaDoc tableInstance = null;
118             Set vtis = rr.visibleTableInstances();
119             int visibleTableInstancesNumber = vtis.size();
120
121             if (0 == visibleTableInstancesNumber) {
122                 Debug.assertTrue(false, "internal logic error");
123             } else if (1 == visibleTableInstancesNumber) {
124                 tableInstance = (Expression) vtis.toArray()[0];
125                 if (!(tableInstance instanceof RenameRelation)) {
126                     tableInstance = new NullPointer();
127                 }
128                 map.put(rr, tableInstance);
129             } else {
130                 Debug.nyi("remove RenameRelation");
131             }
132
133             /* */
134             TopDownReplacer replacer = getReplacerInstance();
135             replacer.setReplaceMap(map);
136
137             ReplaceTractor tractor = getTractorInstance();
138             tractor.setVisitor(replacer);
139             tractor.setEndNode(currentPermiter());
140             //Trace.message(this, "replace map", Debug.pprint(map));
141

142             Expression father = rr.getFather();
143             boolean replaced = father.replaceChild(rr, rr.getOperand());
144             Debug.assertTrue(replaced, "replaced");
145             rr.setFather(null);
146             //Trace.message(this, "leaveScope()", "RenameRelation removed.");
147
father.accept(tractor);
148         }
149     }
150
151     //public void visit(Expression arg) throws SqlWrapperException;
152

153     public void visit(BinaryAlgebra arg) throws SqlWrapperException {
154         //Trace.enter(this, "visit(BinaryAlgebra arg)", arg);
155
/* implementation or Merg, Union, Intersect and difference, but not for OuterJoin */
156         /* here the process of deepth-first serach re-start */
157         createScope();
158         arg.getLeftOperand().accept(this);
159         leaveScope();
160
161         createScope();
162         arg.getRightOperand().accept(this);
163         leaveScope();
164
165         //Trace.exit(this, "visit(BinaryAlgebra arg)", arg);
166
}
167
168     public void visit(BinaryAtomicOp arg) throws SqlWrapperException {
169         //Trace.enter(this, "visit(BinaryAtomicOp arg)", arg);
170

171         createScope();
172         arg.getLeftOperand().accept(this);
173         leaveScope();
174
175         createScope();
176         arg.getRightOperand().accept(this);
177         leaveScope();
178
179         //Trace.exit(this, "visit(BinaryAtomicOp arg)", arg);
180
}
181
182     public void visit(BinOpOuterJoin arg) throws SqlWrapperException {
183         //Trace.enter(this, "visit(BinOpOuterJoin arg)", arg);
184

185         arg.getLeftOperand().accept(this);
186         arg.getRightOperand().accept(this);
187
188         //Trace.exit(this, "visit(BinOpOuterJoin arg)", arg);
189
}
190
191     public void visit(SortSpecification arg) throws SqlWrapperException {
192         //Trace.enter(this, "visit(SortSpecification arg)", arg);
193
Expression sortExpr = arg.getSortExpression();
194         sortExpr.accept(this);
195         //Trace.exit(this, "visit(SortSpecification arg)", arg);
196
}
197
198     public void visit(RenameRelation arg) throws SqlWrapperException {
199         //Trace.enter(this, "visit(RenameRelation arg)", arg);
200

201         /** @todo within a scope, there might be serverl unresolved RenameRelation.
202          * Scope class should keep a list of unresolved RenameRelation instead of one*/

203         if (!(arg.getOperand() instanceof Table || arg.getOperand() instanceof UnOpProject)) {
204             /* when the operand is Table, this RenameRelation should not be removed
205             * when the operand is UnOpProject, this RenameRelation should have been
206             * removed with the UnOpProject */

207             currentScope()._unresolvedRenameRelation = arg;
208             //Trace.message(this, "visit(RenameRelation arg)", "unresolved RenameRelation added to current scope");
209
}
210
211         Expression operand = arg.getOperand();
212         operand.accept(this);
213
214         //Trace.exit(this, "visit(RenameRelation arg)", arg);
215
}
216
217     public void visit(Table arg) throws SqlWrapperException {
218         //Trace.enter(this, "visit(Table arg)", arg);
219
/* here, the process reach a leaf node */
220         //Trace.exit(this, "visit(Table arg)", arg);
221
}
222
223     public void visit(Join arg) throws SqlWrapperException {
224         //Trace.enter(this, "visit(Join arg)", arg);
225

226         List list = arg.getPredicateList();
227         if (null != list) {
228             Expression expr = null;
229             for (int i = 0; i < list.size(); i++) {
230                 expr = (Expression) list.get(i);
231                 createScope();
232                 expr.accept(this);
233                 leaveScope();
234             }
235         }
236
237         list = arg.getOperands();
238         Debug.assertTrue(null != list, "null!=list");
239         Expression expr = null;
240         for (int i = 0; i < list.size(); i++) {
241             expr = (Expression) list.get(i);
242             expr.accept(this);
243         }
244
245         //Trace.exit(this, "visit(Join arg)", arg);
246
}
247
248     public void visit(UnaryAlgebra arg) throws SqlWrapperException {
249         //Trace.enter(this, "visit(UnaryAlgebra arg)", arg);
250

251         List list = arg.getParameterList();
252         if (null != list) {
253             Expression expr = null;
254             for (int i = 0; i < list.size(); i++) {
255                 expr = (Expression) list.get(i);
256                 createScope();
257                 expr.accept(this);
258                 leaveScope();
259             }
260         }
261
262         Expression operand = arg.getOperand();
263         if (isDeletePermitted()) {
264             /* check if this operater permet to delete a underlying UnOpProject*/
265             List opposers = vote(arg.getParameterList());
266             if (null == opposers || opposers.isEmpty()) {
267                 /* do nothing */
268             } else {
269                 permitDelete(arg, false);
270             }
271         }
272         operand.accept(this);
273
274         //Trace.exit(this, "visit(UnaryAlgebra arg)", arg);
275
}
276
277     public void visit(UnaryAtomicOp arg) throws SqlWrapperException {
278         //Trace.enter(this, "visit(UnaryAtomicOp arg)", arg);
279
arg.getOperand().accept(this);
280         //Trace.exit(this, "visit(UnaryAtomicOp arg)", arg);
281
}
282
283     public void visit(UnOpAggregate arg) throws SqlWrapperException {
284         //Trace.enter(this, "visit(UnOpAggregate arg)", arg);
285

286         Expression operand = arg.getOperand();
287
288         /* check if this UnOpAggregate permet to delete a underlying UnOpProject*/
289         createScope();
290         List opposers = vote(arg.getItemList());
291         if (null == opposers || opposers.isEmpty()) {
292             permitDelete(arg, true);
293             //Trace.message(this, "visit(UnOpAggregate arg)", "removal of project is permitted !");
294
}
295         operand.accept(this);
296         leaveScope();
297
298         List itemList = arg.getItemList();
299         Expression item = null;
300         ;
301         for (int i = 0; i < itemList.size(); i++) {
302             createScope();
303             item = (Expression) itemList.get(i);
304             item.accept(this);
305             leaveScope();
306         }
307
308         //Trace.exit(this, "visit(UnOpAggregate arg)", arg);
309
}
310
311     public void visit(UnOpExists arg) throws SqlWrapperException {
312         //Trace.enter(this, "visit(UnOpExists arg)", arg);
313
createScope();
314         boolean doSpecial = false;
315         Expression op = arg.getOperand();
316         if (op instanceof UnOpProject) {
317             if (((UnOpProject)op).getOperand() instanceof Join)
318                 doSpecial = true;
319         }
320         // change LARS 30/10/03 true to false
321
if (doSpecial)
322             permitDelete(arg, false);
323         else
324             permitDelete(arg, true);
325         arg.getOperand().accept(this);
326         leaveScope();
327         //Trace.exit(this, "visit(UnOpExists arg)", arg);
328
}
329
330     public void visit(UnOpProject arg) throws SqlWrapperException {
331         //Trace.enter(this, "visit(UnOpProject arg)", arg);
332

333         Expression operand = arg.getOperand();
334
335         /* visit its operand */
336         //Trace.message(this, "visit(UnOpProject arg)", "Visiting its operand...");
337
createScope();
338         /* check
339         
340         if this UnOpProject permet to delete a underlying UnOpProject*/

341         List opposers = vote(arg.getItemList());
342         if (null == opposers || opposers.isEmpty()) {
343             permitDelete(arg, true);
344             //Trace.message(this, "visit(UnOpProject arg)", "removal of project is permitted !");
345
}
346         operand.accept(this);
347         leaveScope();
348
349         /* visit its items */
350         //Trace.message(this, "visit(UnOpProject arg)", "Visiting its item list...");
351
List itemList = arg.getItemList();
352         Expression item = null;
353         boolean hasAggregateItem = false;
354         if (itemList != null)
355             for (int i = 0; i < itemList.size(); i++) {
356                 createScope();
357                 item = (Expression) itemList.get(i);
358                 item.accept(this);
359                 // Check if this Project contains Aggregate items
360
hasAggregateItem = (item instanceof RenameItem && ((RenameItem)item).getOperand() instanceof UnOpAggregate);
361                 leaveScope();
362             }
363
364         /* remove itself if possible */
365         if (isDeletePermitted()) {
366             if (currentPermiter() instanceof UnOpAggregate) {
367                 // Aggregate items prevent the Project to be removed in an Aggregate
368
if (!hasAggregateItem) {
369                     if (!arg.getDistinct()) {
370                         removeProject(arg, currentPermiter());
371                     } else {
372                         /* @todo verify that currentPermiter contains only aggregation funtions like :
373                          * aggrFunc(attr), but not aggrFunc(*)
374                          */

375                         if (1 == arg.getItemList().size()) {
376                             removeProject(arg, currentPermiter());
377                             ((UnOpAggregate) currentPermiter()).distinctAggregation();
378
379                         } else {
380                             Debug.nyi("1 != arg.getItemList().size()");
381                         }
382                     }
383                 }
384             } else if (!arg.getDistinct()) {
385                 removeProject(arg, currentPermiter());
386             }
387         }
388
389         //Trace.exit(this, "visit(UnOpProject arg)", arg);
390
}
391
392     private void removeProject(UnOpProject project, Expression permittingNode) {
393         //Trace.enter(this, "removeProject(UnOpProject project, Expression permittingNode)");
394

395         //Trace.message(this, "visit(UnOpProject arg)", "starting GoUpVisitor..");
396
HashMap map = makeMap(project);
397
398         /* */
399         TopDownReplacer replacer = getReplacerInstance();
400         replacer.setReplaceMap(map);
401
402         ReplaceTractor tractor = getTractorInstance();
403         tractor.setVisitor(replacer);
404         tractor.setEndNode(currentPermiter());
405         //Trace.message(this, "replace map", Debug.pprint(map));
406

407         Expression father = project.getFather();
408
409         boolean replaced = father.replaceChild(project, project.getOperand());
410         Debug.assertTrue(replaced, "replaced");
411
412         project.setFather(null);
413         //Trace.message(this, "visit(UnOpProject arg)", "project removed.");
414
father.accept(tractor);
415
416         //Trace.exit(this, "removeProject(UnOpProject project, Expression permittingNode)");
417
}
418
419     private List vote(List exprList) {
420         return null;
421         // Trace.enter(this,"vote(List exprList)");
422
//
423
// _voteVisitor.reinit();
424
// Expression expr = null;
425
// for (int i = 0; i < exprList.size(); i++) {
426
// expr = (Expression)exprList.get(i);
427
// expr.accept(_voteVisitor);
428
// }
429
// List retVal = _voteVisitor.getOpposerList();
430
//
431
// Trace.exit(this,"vote(List exprList)");
432
// return retVal;
433
}
434
435     private HashMap makeMap(UnOpProject arg) {
436         //Trace.enter(this, "makeMap(UnOpProject arg))", arg.pprint());
437

438         HashMap retVal = new HashMap();
439         List itemList = arg.getItemList();
440         Expression item = null;
441         String JavaDoc attrName = null;
442         AttributeExpression attrExpr = null;
443         Expression replacer = null;
444         XQueryExpression originalXExpr = null;
445
446         if (itemList != null)
447             for (int i = 0; i < itemList.size(); i++) {
448                 item = (Expression) itemList.get(i);
449                 attrName = item.getName();
450                 attrExpr = new AttributeExpression(null, attrName);
451
452                 // originalXExpr = item.getOrginalXExpr();
453
// Debug.assertTrue(null != originalXExpr, "null != originalXExpr" + item.pprint());
454

455                 replacer = findReplacer(item);
456                 retVal.put(attrExpr, replacer);
457             }
458
459         /* create a map item for "*" */
460         Set vtiSet = arg.visibleTableInstances();
461         if (1 == vtiSet.size()) {
462             Expression vti = (Expression) vtiSet.toArray()[0];
463             if (vti instanceof RenameRelation) {
464                 attrExpr = new AttributeExpression(null, "*");
465                 replacer = new AttributeExpression((RenameRelation) vti, "*");
466                 retVal.put(attrExpr, replacer);
467             }
468         }
469
470         //Trace.exit(this, "makeMap(UnOpProject arg))", arg.pprint());
471
return retVal;
472     }
473
474     private Expression findReplacer(Expression item) {
475         //Trace.enter(this, "findReplacer(Expression item)", item.pprint());
476

477         Expression retVal = null;
478
479         if (item instanceof RenameItem) {
480             retVal = ((RenameItem) item).getOperand();
481             retVal = findReplacer(retVal);
482         }
483         // else if (item instanceof AttributeExpression) {
484
// retVal = ((AttributeExpression)item).getUnderlyinExpr();
485
// if (retVal instanceof Attribute) {
486
// /* item is the first AttributeExpression who refer a Attribute */
487
// retVal = item;
488
// }
489
// retVal = item;
490
// }
491
else {
492             retVal = item;
493             // Debug.assertTrue(false,"internal logic error");
494
}
495
496         //Trace.exit(this, "findReplacer(Expression item)", item.pprint());
497
return retVal;
498     }
499
500     class Scope {
501         private static final String JavaDoc RCSRevision = "$Revision: 1.7 $";
502         private static final String JavaDoc RCSName = "$Name: $";
503
504         boolean _deletePermited = false;
505         Expression _node = null;
506         RenameRelation _unresolvedRenameRelation = null;
507         Scope() {
508         }
509         Scope(Expression node, boolean deletePermited) {
510             _node = node;
511             _deletePermited = deletePermited;
512         }
513     }
514
515     final class ReplaceTractor extends BottomUpTractor {
516         ReplaceTractor() {
517             super();
518         }
519
520         public void visit(RenameRelation arg) throws SqlWrapperException {
521             //Trace.enter(this, "visit(RenameRelation arg)", arg);
522

523             /* set arg to "TableInstance" attribute for all AttributExpression*/
524             Map map = ((TopDownReplacer) getVisitor()).getReplaceMap();
525
526             HashMap newMap = new HashMap();
527             Set keySet = map.keySet();
528             Iterator iter = keySet.iterator();
529             AttributeExpression item = null;
530             Object JavaDoc value = null;
531             while (iter.hasNext()) {
532                 item = (AttributeExpression) iter.next();
533                 value = map.get(item);
534
535                 item.setTableInstance(arg);
536                 newMap.put(item, value);
537             }
538
539             ((TopDownReplacer) getVisitor()).setReplaceMap(newMap);
540
541             //Trace.message(this, "visit(RenameRelation arg)", "updated replac map :" + Debug.pprint(newMap));
542

543             /* remove this node */
544             Expression father = arg.getFather();
545             boolean replaced = father.replaceChild(arg, arg.getOperand());
546             Debug.assertTrue(replaced, "replaced");
547             arg.setFather(null);
548             //Trace.message(this, "visit(RenameRelation arg)", "RenameRelation removed");
549

550             if (getEndNode() != arg) {
551                 father.accept(this);
552             }
553
554             //Trace.exit(this, "visit(RenameRelation arg)", arg);
555
}
556
557         public void visit(UnOpProject arg) throws SqlWrapperException {
558             //Trace.enter(this, "UnOpProject(Join arg)", arg.pprint());
559

560             List list = arg.getParameterList();
561
562             if (null != list) {
563                 treat(list);
564             }
565
566             UnOpSort sort = arg.getAssociatedSort();
567             if (null != sort) {
568                 SortSpecification spec = null;
569                 list = sort.getSortSpecificationList();
570                 treat(list);
571             }
572
573             visitFather(arg);
574
575             //Trace.exit(this, "UnOpProject(Join arg)", arg.pprint());
576
}
577     }
578 }
579
Popular Tags