KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > medor > optim > jorm > JormFlatten2Rdb


1 /**
2  * MEDOR: Middleware Enabling Distributed Object Requests
3  *
4  * Copyright (C) 2001-2005 France Telecom R&D
5  * Contact: alexandre.lefebvre@rd.francetelecom.com
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20  *
21  * Initial developers: M. Alia, S. Chassande-Barrioz, A. Lefebvre
22  */

23 package org.objectweb.medor.optim.jorm;
24
25 import java.util.ArrayList JavaDoc;
26 import java.util.Collection JavaDoc;
27 import java.util.HashMap JavaDoc;
28 import java.util.Iterator JavaDoc;
29 import java.util.List JavaDoc;
30 import java.util.Map JavaDoc;
31
32 import org.objectweb.jorm.api.PClassMapping;
33 import org.objectweb.jorm.api.PException;
34 import org.objectweb.jorm.api.PMapper;
35 import org.objectweb.jorm.mapper.rdb.adapter.RdbAdapterFactory;
36 import org.objectweb.jorm.mapper.rdb.adapter.api.JoinedTable;
37 import org.objectweb.jorm.mapper.rdb.adapter.api.RdbAdapterException;
38 import org.objectweb.jorm.mapper.rdb.lib.RdbPPolymorphicClass;
39 import org.objectweb.jorm.mapper.rdb.metainfo.RdbClassMultiMapping;
40 import org.objectweb.jorm.mapper.rdb.metainfo.RdbExternalTable;
41 import org.objectweb.jorm.mapper.rdb.metainfo.RdbGenClassMapping;
42 import org.objectweb.jorm.mapper.rdb.metainfo.RdbJoin;
43 import org.objectweb.jorm.mapper.rdb.metainfo.RdbPrimitiveElementMapping;
44 import org.objectweb.jorm.mapper.rdb.metainfo.RdbTable;
45 import org.objectweb.jorm.metainfo.api.Class;
46 import org.objectweb.jorm.metainfo.api.GenClassRef;
47 import org.objectweb.jorm.metainfo.api.NameDef;
48 import org.objectweb.jorm.metainfo.api.PrimitiveElement;
49 import org.objectweb.jorm.naming.api.PName;
50 import org.objectweb.jorm.type.api.PType;
51 import org.objectweb.medor.api.Field;
52 import org.objectweb.medor.api.MedorException;
53 import org.objectweb.medor.datasource.api.DataStore;
54 import org.objectweb.medor.datasource.lib.ConnectionFactoryDataStore;
55 import org.objectweb.medor.expression.api.BinaryLogicalOperator;
56 import org.objectweb.medor.expression.api.Comparator;
57 import org.objectweb.medor.expression.api.Expression;
58 import org.objectweb.medor.expression.api.ExpressionException;
59 import org.objectweb.medor.expression.api.MalformedExpressionException;
60 import org.objectweb.medor.expression.api.Operand;
61 import org.objectweb.medor.expression.api.Operator;
62 import org.objectweb.medor.expression.api.ParameterOperand;
63 import org.objectweb.medor.expression.api.VariableOperand;
64 import org.objectweb.medor.expression.lib.And;
65 import org.objectweb.medor.expression.lib.BasicVariableOperand;
66 import org.objectweb.medor.expression.lib.Equal;
67 import org.objectweb.medor.expression.lib.Not;
68 import org.objectweb.medor.expression.lib.NotEqual;
69 import org.objectweb.medor.expression.lib.Or;
70 import org.objectweb.medor.filter.api.FieldOperand;
71 import org.objectweb.medor.filter.jorm.lib.CompositePName;
72 import org.objectweb.medor.filter.jorm.lib.EncodePName;
73 import org.objectweb.medor.filter.jorm.lib.SinglePName;
74 import org.objectweb.medor.filter.lib.BasicFieldOperand;
75 import org.objectweb.medor.filter.lib.Count;
76 import org.objectweb.medor.filter.lib.ExpressionPrinter;
77 import org.objectweb.medor.filter.lib.IsEmpty;
78 import org.objectweb.medor.filter.lib.IsNull;
79 import org.objectweb.medor.filter.lib.MemberOf;
80 import org.objectweb.medor.optim.api.RewriteRule;
81 import org.objectweb.medor.optim.lib.PushNotInExpressionRule;
82 import org.objectweb.medor.query.api.CalculatedField;
83 import org.objectweb.medor.query.api.OrderField;
84 import org.objectweb.medor.query.api.PropagatedField;
85 import org.objectweb.medor.query.api.QueryNode;
86 import org.objectweb.medor.query.api.QueryTree;
87 import org.objectweb.medor.query.api.QueryTreeField;
88 import org.objectweb.medor.query.jorm.api.JormExtent;
89 import org.objectweb.medor.query.jorm.lib.ClassExtent;
90 import org.objectweb.medor.query.jorm.lib.PNameField;
91 import org.objectweb.medor.query.lib.BasicCalculatedField;
92 import org.objectweb.medor.query.lib.BasicOrderField;
93 import org.objectweb.medor.query.lib.Nest;
94 import org.objectweb.medor.query.lib.QueryTreePrinter;
95 import org.objectweb.medor.query.lib.SelectProject;
96 import org.objectweb.medor.query.rdb.api.QualifiedTable;
97 import org.objectweb.medor.query.rdb.api.RdbExpField;
98 import org.objectweb.medor.query.rdb.api.RdbExpQueryLeaf;
99 import org.objectweb.medor.query.rdb.api.RdbField;
100 import org.objectweb.medor.query.rdb.lib.BasicQualifiedTable;
101 import org.objectweb.medor.query.rdb.lib.BasicRdbExpQueryLeaf;
102 import org.objectweb.util.monolog.api.BasicLevel;
103
104 /**
105  * This rules transforms a QueryTree built on top of JORM Extents into
106  * a QueryTree built on top of RdbExpQueryLeaves.
107  * <p>The initial QueryTree can be a JORM Extent, or composed of one QueryNode
108  * with one or several JORM Extent. The FlattenQueryTree rewriting rule can
109  * produce such a QueryTree.</p>
110  * <p>The resulting QueryTree always has a SelectProject node on top of the
111  * RdbExpQueryLeaf, in case of CalculatedFields (for example the PName).</p>
112  *
113  * @author S. Chassande-Barrioz
114  */

115 public class JormFlatten2Rdb extends JormRule {
116
117     public JormFlatten2Rdb() {
118         super("JormFlatten2Rdb");
119     }
120
121     /**
122      * element = JormExtent
123      */

124     private List JavaDoc extents = new ArrayList JavaDoc();
125
126     /**
127      * element = RdbJormExtentMapping
128      */

129     private List JavaDoc mappings = new ArrayList JavaDoc();
130
131     /**
132      * element = BasicRdbExpQueryLeaf
133      */

134     private List JavaDoc subLeaves = new ArrayList JavaDoc();
135
136     /**
137      * This field is used as counter for calculating the table alias name.
138      */

139     private int alias = 0;
140
141     private List JavaDoc joinedTables = new ArrayList JavaDoc();
142
143     /**
144      * These two fields are used to map new MemberOf operators (created from the
145      * existing ones) with the extent of
146      * the fields on the right hand side of the MemberOf
147      */

148     private List JavaDoc mofs = new ArrayList JavaDoc();
149     private List JavaDoc mofExtents = new ArrayList JavaDoc();
150     private List JavaDoc empties = new ArrayList JavaDoc();
151
152     public QueryTree rewrite(QueryTree qt, QueryNode parent)
153             throws MedorException {
154         log.log(BasicLevel.DEBUG, "JormFlatten2Rdb: Input query tree:");
155         QueryTreePrinter.printQueryTree(qt, log, BasicLevel.DEBUG);
156         extents.clear();
157         mappings.clear();
158         alias = 0;
159         joinedTables.clear();
160         mofs.clear();
161         mofExtents.clear();
162         empties.clear();
163         subLeaves.clear();
164         //Map of replaced fields, for propagation to the Parent.
165
Map JavaDoc localyReplaced = (parent == null ? null : new HashMap JavaDoc());
166
167         if (qt instanceof JormExtent) {
168             SelectProject p = new SelectProject("");
169             Field[] fs = qt.getTupleStructure().getFields();
170             for (int i = 0; i < fs.length; i++) {
171                 Field newF =
172                         p.addPropagatedField(fs[i].getName(), fs[i].getType(),
173                                 new QueryTreeField[]{(QueryTreeField) fs[i]});
174                 if (parent != null) {
175                     localyReplaced.put(fs[i], newF);
176                 }
177             }
178             /*
179             Iterator lrit = localyReplaced.keySet().iterator();
180             for (int lri = 0; lri < localyReplaced.size(); lri++) {
181                 Object lrentry = lrit.next();
182                 log.log(BasicLevel.DEBUG, "entry: " + lrentry);
183                 log.log(BasicLevel.DEBUG, "new:" + localyReplaced.get(lrentry));
184             }
185             */

186             replaceUsage(parent, localyReplaced);
187             return rewrite(p, parent);
188         }
189         QueryNode qn = (QueryNode) qt;
190         QueryTree[] children = qn.getChildren();
191         for (int i = 0; i < children.length; i++) {
192             //add the pkAndFields boolean parameter
193
RdbJormExtentMapping rjem =
194                     new RdbJormExtentMapping((JormExtent) children[i]);
195             rjem.outer = qn.isOuter(children[i]);
196             extents.add(children[i]);
197             mappings.add(rjem);
198         }
199         Expression filter;
200         boolean assignfilter = false;
201         try {
202             filter = qn.getQueryFilter();
203             assignfilter = (filter != null);
204         }
205         catch (Exception JavaDoc e) {
206             filter = null;
207         }
208         if (debug) {
209             log.log(BasicLevel.DEBUG, "The initial structure values");
210             for (int i = 0; i < mappings.size(); i++) {
211                 log.log(BasicLevel.DEBUG, "Extent " + ((RdbJormExtentMapping) mappings.get(i)).extent.getName());
212                 log.log(BasicLevel.DEBUG, "Extent tables size " + ((RdbJormExtentMapping) mappings.get(i)).tables.size());
213                 QualifiedTable quali = ((QualifiedTable) ((RdbJormExtentMapping) mappings.get(i)).tables.get(0));
214                 log.log(BasicLevel.DEBUG, "Extent table 0 " + quali.getTableName());
215                 log.log(BasicLevel.DEBUG, "Extent table alias 0 " + quali.getAliasName());
216                 log.log(BasicLevel.DEBUG, "Join size " + ((RdbJormExtentMapping) mappings.get(i)).joins.size());
217                 //log.log(BasicLevel.DEBUG, "Join 0 name " + ((Join)((RdbJormExtentMapping)mappings.get(i)).joins.get(0)).name);
218
//log.log(BasicLevel.DEBUG, "Join 0 columns " + ((Join)((RdbJormExtentMapping)mappings.get(i)).joins.get(0)).columns.length);
219

220                 log.log(BasicLevel.DEBUG, mappings.get(i));
221             }
222             //log.log(BasicLevel.DEBUG, "filter: " + ExpressionPrinter.e2str(filter));
223
log.log(BasicLevel.DEBUG, "Removing useless pname equality");
224         }
225         filter = removeUseLessPNameEquality(filter);
226         if (debug) {
227             for (int i = 0; i < mappings.size(); i++) {
228                 log.log(BasicLevel.DEBUG, mappings.get(i));
229             }
230             log.log(BasicLevel.DEBUG, "filter: " + ExpressionPrinter.e2str(filter));
231             log.log(BasicLevel.DEBUG, "Updating the projected fields");
232         }
233
234         // Create the rdb leaf with its datastore
235
DataStore ds = ((JormExtent) children[0]).getDataStore();
236         String JavaDoc databasename =
237                 ((JormExtent) children[0]).getPMapper().getMapperName();
238         int idx = databasename.indexOf('.');
239         if (idx != -1) {
240             databasename = databasename.substring(idx + 1);
241         } else {
242             databasename = RdbAdapterFactory.DATABASE_NAME_JDBC;
243         }
244         if (ds == null) {
245             Object JavaDoc cf =
246                 ((JormExtent) children[0]).getPMapper().getConnectionFactory();
247             ds = new ConnectionFactoryDataStore(
248                     DataStore.JDBC_STORE,
249                     cf.toString(),
250                     new short[0],
251                     cf);
252         }
253         BasicRdbExpQueryLeaf leaf = new BasicRdbExpQueryLeaf(ds, "");
254         boolean distinctLeafForCountAll = false;
255         try {
256             leaf.setRdbAdapter(RdbAdapterFactory.getTypeConverter(databasename));
257         }
258         catch (RdbAdapterException e) {
259             throw new MedorException(
260                     "Impossible to assign the rdb adapter to the leaf", e);
261         }
262         Field[] fs = qt.getTupleStructure().getFields();
263         for (int i = 0; i < fs.length; i++) {
264             if (fs[i] instanceof PropagatedField) {
265                 QueryTreeField qtf = (QueryTreeField)
266                         ((PropagatedField) fs[i]).getPreviousFields()[0];
267                 if (qtf instanceof PNameField) {
268                     //Does the parent perform a Count of the PNameField ?
269
Count countexp = fieldUsedInCount(qtf, parent);
270                     if (countexp == null) {
271                         if (debug) log.log(BasicLevel.DEBUG, "Regularly used PName");
272                         CalculatedField cf = new BasicCalculatedField(
273                                 qtf.getName(), qtf.getType(), qtf.getQueryTree(),
274                                 getDecode((PNameField) qtf, leaf, true));
275                         if (debug) log.log(BasicLevel.DEBUG, "Replacing PName with calculated field (old " + fs[i] + ", new "+ cf + ")");
276                         qn.replace((QueryTreeField) fs[i], cf);
277                         if (parent != null) {
278                             localyReplaced.put(fs[i], cf);
279                         }
280                     } else {
281                         if (debug) log.log(BasicLevel.DEBUG, "Found a count");
282
283                         /* It is a Count(PName). In this case:
284                         - singlePName : replace with single field
285                         - compositePName : propagate PName fields (getField) and
286                         indicates to Count that it does not have an expression
287                         */

288                         JormExtent extent = (JormExtent) qtf.getQueryTree();
289                         if (debug) {
290                             log.log(BasicLevel.DEBUG, "in extent " + extent.getJormName());
291                         }
292                         log.log(BasicLevel.DEBUG, "Looking for NameDef of " + qtf);
293                         NameDef nd = ((PNameField)qtf).getNameDef(extent);
294                         if (nd.isFieldName()) { //single PName
295
QueryTreeField newf =
296                                     getField(nd.getFieldName(), extent, leaf, true);
297                             qn.updatePropagatedField(
298                                 fs[i].getName(), new QueryTreeField[]{newf});
299                             log.log(BasicLevel.DEBUG, "New field for single PName " + newf);
300                         } else if (nd.isNameRef()) { //multiple PName
301
Map JavaDoc proj = nd.getNameRef().getProjection();
302                             QueryTreeField newqtf = null;
303                             QueryTreeField[] newqtfT = new QueryTreeField[proj.entrySet().size()];
304                             int j = 0;
305                             for (Iterator JavaDoc it = proj.entrySet().iterator(); it.hasNext();) {
306                                 Map.Entry JavaDoc me = (Map.Entry JavaDoc) it.next();
307                                 String JavaDoc clafn = (String JavaDoc) me.getValue();
308                                 newqtf = getField(clafn, extent, leaf, true);
309                                 newqtfT[j] = newqtf;
310                                 j++;
311                             }
312                             log.log(BasicLevel.DEBUG, "New field for composite PName " + newqtf);
313                             qn.updatePropagatedField(fs[i].getName(), newqtfT);
314                             if (proj.size() > 1) {
315                                 log.log(BasicLevel.INFO, "Count on multiple fields: no other aggregate functions should be allowed");
316                                 countexp.setCountAll();
317                                 //if distinct on count in this case, move the
318
//distinct to the underlying node
319
distinctLeafForCountAll = true;
320                             }
321                         }
322
323                     }
324                 } else {
325                     QueryTreeField f = getField(qtf, leaf, true);
326                     qn.updatePropagatedField(
327                             fs[i].getName(), new QueryTreeField[]{f});
328                 }
329             } else if (fs[i] instanceof CalculatedField) {
330                 Expression e = ((CalculatedField) fs[i]).getExpression();
331                 try {
332                     e = updateFieldOfExpression(e, leaf, true);
333                 }
334                 catch (ExpressionException e1) {
335                     throw new MedorException(e1);
336                 }
337                 qn.updateCalculatedField(fs[i].getName(), e);
338             } else {
339                 throw new MedorException(
340                         "Unmanaged field (" + fs[i].getName() + "): " + fs[i]);
341             }
342         }
343         /*
344         Iterator lrit = localyReplaced.keySet().iterator();
345         for (int lri = 0; lri < localyReplaced.size(); lri++) {
346             Object lrentry = lrit.next();
347             log.log(BasicLevel.DEBUG, "entry: " + lrentry);
348             log.log(BasicLevel.DEBUG, "new:" + localyReplaced.get(lrentry));
349         }
350         */

351         replaceUsage(parent, localyReplaced);
352         if (debug) {
353             log.log(BasicLevel.DEBUG, "Updating the order by clause");
354         }
355         OrderField[] ofields = qt.getOrderBy();
356         if (ofields != null) {
357             for (int j = 0; j < ofields.length; j++) {
358                 QueryTreeField f = getField(ofields[j].getField(), leaf, false);
359                 ofields[j].setField(f);
360             }
361         }
362         if (debug) {
363             log.log(BasicLevel.DEBUG, "Updating the filter");
364         }
365         try {
366             filter = updateFieldOfExpression(filter, leaf, false);
367         }
368         catch (ExpressionException e) {
369             throw new MedorException(e);
370         }
371         if (debug) {
372             log.log(BasicLevel.DEBUG, "filter: " + ExpressionPrinter.e2str(filter));
373         }
374         if (assignfilter) {
375             qn.setQueryFilter(null);
376         }
377         leaf.setQueryFilter(filter);
378         leaf.setRootJoinedTables(joinedTables);
379         if (debug) {
380             log.log(BasicLevel.DEBUG, "joinedTables: " + joinedTables);
381             log.log(BasicLevel.DEBUG, "JormFlatten2Rdb: Query leaf expression:");
382             log.log(BasicLevel.DEBUG, ExpressionPrinter.e2str(filter));
383         }
384
385         //Push the not in the expression before to split the filter due to the
386
// member of.
387
RewriteRule rule = new PushNotInExpressionRule();
388         //TODO check relationship with parent QueryNode parameter
389
rule.rewrite(leaf, null);
390         filter = leaf.getQueryFilter();
391
392         splitLeaf(leaf, filter);
393         //propagates the distinct in case of count(CompositePName)
394
leaf.setDistinct(distinctLeafForCountAll ? true : qt.getDistinct());
395         //sets the query leaf as a subquery in the case of aggregates
396
leaf.setIsSubquery(distinctLeafForCountAll);
397         //propagates the order by to the leaf
398
if (ofields != null) {
399             OrderField[] leafOFields =
400                     new BasicOrderField[ofields.length];
401             for (int j = 0; j < ofields.length; j++) {
402                 OrderField of = new BasicOrderField(
403                         ofields[j].getField(),
404                         ofields[j].getDesc()
405                 );
406                 leafOFields[j] = of;
407             }
408             leaf.setOrderBy(leafOFields);
409         }
410         leaf.setQueryFilter(updateFilterWithNewLeaves(filter, leaf));
411         log.log(BasicLevel.DEBUG, "JormFlatten2Rdb: Output query tree:");
412         QueryTreePrinter.printQueryTree(qt, log, BasicLevel.DEBUG);
413         return qt;
414     }
415
416
417     /**
418      * Represents the mapping of a JormExtent over relational tables.
419      * <p>Only the
420      * main table and the external not collocated table are listed in a node.
421      */

422     public class RdbJormExtentMapping {
423
424         /**
425          * The extent which is mapped.
426          */

427         private JormExtent extent = null;
428
429         /**
430          * Whether the tables from this extent should be outer joined or not.
431          **/

432         private boolean outer = true;
433
434         /**
435          * List of tables inside which the extent is mapped.
436          * <p>This list contains
437          * only the main table and the not collocated external tables.
438          * The first element of the list is the main table.
439          * element = QualifiedTable
440          */

441         private List JavaDoc tables = new ArrayList JavaDoc(5);
442
443         /**
444          * List of join to reach the table.
445          * <p>This list is linked to the tables
446          * list. The first element is always null because the main table does
447          * not need a join.
448          * element = Join
449          */

450         private List JavaDoc joins = new ArrayList JavaDoc(5);
451
452         public RdbJormExtentMapping(JormExtent je) throws MedorException {
453             setJormExtent(je);
454         }
455
456         /**
457          * Assigns the JormExtent and calculates the fields 'tables'
458          * and 'joins'.
459          * @param je is a JormExtent instance (ClassExtent or GenClassExtent)
460          * @throws MedorException if the jorm meta information is malformed
461          */

462         public void setJormExtent(JormExtent je) throws MedorException {
463             extent = je;
464             if (extent.getMetaObject() instanceof Class JavaDoc) {
465                 RdbClassMultiMapping cm =
466                         (RdbClassMultiMapping) getClassMapping(extent);
467                 RdbTable maintable = cm.getRdbTable();
468                 Class JavaDoc cl = (Class JavaDoc) cm.getLinkedMO();
469                 boolean isPolymorphic = cl.isPolymorphic();
470                 String JavaDoc tableName = maintable.getName();
471                 String JavaDoc alias = "";
472                 String JavaDoc query = "( ";
473                 if (isPolymorphic) {
474                     //get the mapper
475
PMapper mapper = extent.getPMapper();
476                     //get the PClassMapping
477
PClassMapping pcm = mapper.lookup(cl.getFQName());
478                     String JavaDoc primaryKey = ((RdbPPolymorphicClass)pcm).getPNameFields();
479                     if (je.withSubClasses()) {
480                         query += cm.getRdbInheritanceQuery().getExtentQuery(
481                                 mapper,
482                                 ((ClassExtent)extent).isPrefetch(),
483                                 false,
484                                 primaryKey,
485                                 pcm);
486                     } else {
487                         RdbPPolymorphicClass polymorphicPCM = (RdbPPolymorphicClass) pcm;
488                         try {
489                             query += polymorphicPCM.getExtentQuery(true);
490                         } catch (PException e) {
491                             throw new MedorException(e);
492                         }
493                     }
494                     query += ")";
495                     alias = getQueryAlias(tableName);
496                 } else {
497                     alias = getTableAlias(maintable, null);
498                 }
499                 QualifiedTable mainqtable = new BasicQualifiedTable(
500                         (isPolymorphic?query:tableName),
501                         alias,
502                         isPolymorphic);
503                 tables.add(mainqtable);
504                 joins.add(null);
505                 
506                 //stop here if the class has subclasses or superclasses
507
if (isPolymorphic)
508                     return;
509                 
510                 Collection JavaDoc etables = cm.getRdbExternalTables();
511                 Iterator JavaDoc tableit = etables.iterator();
512                 while (tableit.hasNext()) {
513                     RdbExternalTable etable = (RdbExternalTable) tableit.next();
514                     Collection JavaDoc rdbJjoins = etable.getRdbJoins();
515                     Iterator JavaDoc joinit = rdbJjoins.iterator();
516                     if (!joinit.hasNext()) {
517                         throw new MedorException(
518                                 "No join defined for the external table "
519                                 + etable.getName() + " in the extent "
520                                 + je.getJormName());
521                     }
522                     while (joinit.hasNext()) {
523                         RdbJoin j = (RdbJoin) joinit.next();
524                         Join join = new Join(j, maintable, etable);
525                         joins.add(join);
526                         QualifiedTable qtable =
527                                 new BasicQualifiedTable(etable.getName(),
528                                         getTableAlias(etable, j));
529                         tables.add(qtable);
530                     }
531                 }
532             } else if (extent.getMetaObject() instanceof GenClassRef) {
533                 RdbGenClassMapping gcm =
534                         (RdbGenClassMapping) getGenClassMapping(extent);
535                 RdbTable maintable = gcm.getRdbTable();
536                 QualifiedTable mainqtable = new BasicQualifiedTable(
537                         maintable.getName(),
538                         getTableAlias(maintable, null));
539                 tables.add(mainqtable);
540                 joins.add(null);
541             }
542         }
543
544         public int getJoinIndex(String JavaDoc joinname) throws MedorException {
545             for (int i = 1; i < joins.size(); i++) {
546                 if (joinname.equals(((Join) joins.get(i)).name)) {
547                     return i;
548                 }
549             }
550             throw new MedorException("Join " + joinname
551                     + " not found in the extent of the class "
552                     + extent.getJormName());
553         }
554
555         public String JavaDoc toString() {
556             StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
557             sb.append("* ExtentMapping: ");
558             sb.append(extent.getJormName());
559             sb.append("\n");
560             sb.append("Tables:\n");
561             for (int i = 0; i < tables.size(); i++) {
562                 QualifiedTable qt = (QualifiedTable) tables.get(i);
563                 sb.append(qt.getAliasName());
564                 sb.append(" join: ");
565                 if (joins.get(i) != null) {
566                     sb.append(joins.get(i));
567                 }
568                 sb.append("\n");
569             }
570             return sb.toString();
571         }
572     }
573
574     /**
575      * A join linking two relational tables.
576      */

577     public class Join {
578
579         /**
580          * the join name is used in the table alias in order to avoid name
581          * collision in case of multiple joins toward a same table.
582          */

583         public String JavaDoc name = "";
584
585         /**
586          * is a list of JoinColumn instance.
587          */

588         public JoinColumn[] columns = null;
589
590         /**
591          * Builds a Join between a main table and an external table.
592          * The Join is equal to the name of the jorm meta object describing the
593          * join.
594          * @param j is the jorm meta object describing the join.
595          * @param maintable is the jorm meta object describing the main table
596          * @param externaltable is the jorm meta object describing the
597          * external table.
598          */

599         public Join(RdbJoin j, RdbTable maintable, RdbTable externaltable) {
600             name = j.getName();
601             List JavaDoc mcols = j.getPTJoinColumnNames();
602             List JavaDoc ecols = j.getETJoinColumnNames();
603             columns = new JoinColumn[ecols.size()];
604             for (int i = 0; i < ecols.size(); i++) {
605                 JoinColumn jc = new JoinColumn();
606                 jc.column1 = (String JavaDoc) mcols.get(i);
607                 jc.column2 = (String JavaDoc) ecols.get(i);
608                 RdbPrimitiveElementMapping pem =
609                         (RdbPrimitiveElementMapping) maintable
610                         .getPrimitiveElementMappingByCol(jc.column1);
611                 PrimitiveElement pe = (PrimitiveElement) pem.getLinkedMO();
612                 jc.type = pe.getType();
613                 jc.field1 = pe.getName();
614                 pem = (RdbPrimitiveElementMapping) externaltable
615                         .getPrimitiveElementMappingByCol(jc.column2);
616                 if (pem != null) {
617                     pe = pem.lookupPrimitiveElement(j);
618                     jc.field2 = pe.getName();
619                 }
620                 columns[i] = jc;
621             }
622         }
623
624         public String JavaDoc toString() {
625             StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
626             sb.append(name);
627             String JavaDoc sep = "{";
628             for (int i = 0; i < columns.length; i++) {
629                 sb.append(sep);
630                 sb.append(columns[i]);
631                 sep = " && ";
632             }
633             sb.append('}');
634             return sb.toString();
635         }
636     }
637
638     /**
639      * It describes the join between two columns
640      */

641     public class JoinColumn {
642
643         /**
644          * Both fields have the same jorm type.
645          */

646         public PType type = null;
647
648         /**
649          * Name of the first jorm field
650          */

651         public String JavaDoc field1 = null;
652
653         /**
654          * Name of the first column name
655          */

656         public String JavaDoc column1 = null;
657
658         /**
659          * Name of the second jorm field
660          */

661         public String JavaDoc field2 = null;
662
663         /**
664          * Name of the second column name
665          */

666         public String JavaDoc column2 = null;
667
668         public String JavaDoc toString() {
669             return "(" + column1 + " = " + column2 + ")";
670         }
671     }
672
673     /**
674      * Retrieves the RdbJormExtentMapping at the position i the packet.
675      * @param i is position of the expected RdbJormExtentMapping
676      * @return a RdbJormExtentMapping (never null).
677      */

678     public RdbJormExtentMapping getMapping(int i) {
679         return (RdbJormExtentMapping) mappings.get(i);
680     }
681
682     /**
683      * Retrieves the RdbJormExtentMapping at the position i the packet.
684      * @param je is the jorm extent which the mapping is expected
685      * @return a RdbJormExtentMapping (never null).
686      */

687     public RdbJormExtentMapping getMapping(JormExtent je) {
688         int i = extents.indexOf(je);
689         return (i == -1 ? null : (RdbJormExtentMapping) mappings.get(i));
690     }
691
692     /**
693      * Calculates the table alias.
694      * @param table is the tablt which the alias is expected.
695      * @param join is the join to use to reach the table. This field can be null
696      * if the table is the main.
697      * @return a string value which is the alias of the table (never null).
698      */

699     private String JavaDoc getTableAlias(RdbTable table, RdbJoin join) {
700         return (join == null
701                 ? table.getName() + "_" + (alias++)
702                 : table.getName() + "_" + (alias++) + "_" + join.getName());
703     }
704
705     /**
706      * Computes the query alias
707      * @param tableName is the name of the main table
708      */

709     private String JavaDoc getQueryAlias(String JavaDoc tableName){
710         return tableName + "_" + (alias++);
711     }
712     
713     /**
714      * Merges the useless tables and removes the useless PName equalities. This
715      * method is recursive.
716      * @param e the current expression
717      * @return the new expression. If the value is null then that means the
718      * expression given in paremter is useless. if the value is different from
719      * the parameter then that means the expression has been modified and this
720      * is the new value.
721      * @throws MedorException if an arror occurs during the merging of table
722      * or if the expressin is malformed.
723      */

724     private Expression removeUseLessPNameEquality(Expression e)
725             throws MedorException {
726         if (e == null) {
727             return null;
728         }
729         if (e instanceof Equal) {
730             Equal eq = (Equal) e;
731             Expression left = eq.getExpression(0);
732             Expression right = eq.getExpression(1);
733             if (left instanceof FieldOperand && right instanceof FieldOperand) {
734                 FieldOperand fo1 = (FieldOperand) left;
735                 FieldOperand fo2 = (FieldOperand) right;
736                 QueryTreeField qtf1 = (QueryTreeField) fo1.getField();
737                 QueryTreeField qtf2 = (QueryTreeField) fo2.getField();
738                 if (qtf1 instanceof PNameField & qtf2 instanceof PNameField) {
739                     //This is a PName equality
740

741                     PNameField pnf1 = (PNameField) qtf1;
742                     JormExtent je1 = (JormExtent) pnf1.getQueryTree();
743                     log.log(BasicLevel.DEBUG, "JormExtent: " + je1 + " " + je1.getName());
744                     log.log(BasicLevel.DEBUG, "PNameField: " + pnf1.getName());
745                     NameDef nd1 = pnf1.getNameDef(je1);
746                     log.log(BasicLevel.DEBUG, "NameDef1: " + nd1);
747
748                     PNameField pnf2 = (PNameField) qtf2;
749                     JormExtent je2 = (JormExtent) pnf2.getQueryTree();
750                     NameDef nd2 = pnf2.getNameDef(je2);
751                     log.log(BasicLevel.DEBUG, "NameDef2: " + nd2);
752
753                     boolean sameTable = true;
754                     if (nd1.isFieldName() && nd2.isFieldName()) {
755                         //Replace if the column are the same
756
sameTable = sameColumn(je1, nd1.getFieldName(),
757                                 je2, nd2.getFieldName(), true);
758                     } else if (nd1.isNameRef() && nd2.isNameRef()) {
759                         if (!nd1.getNameRef().getCompositeName().getFQName()
760                                 .equals(
761                                         nd2.getNameRef().getCompositeName().getFQName())) {
762                             throw new MedorException("Bad PName equality: " +
763                                     "two different composite name");
764                         }
765                         Map JavaDoc proj1 = nd1.getNameRef().getProjection();
766                         Map JavaDoc proj2 = nd2.getNameRef().getProjection();
767                         if (proj1.size() != proj2.size()) {
768                             throw new MedorException(
769                                     "Bad PName equality: bad projection size");
770                         }
771                         Iterator JavaDoc it = proj1.entrySet().iterator();
772                         //Replace if all columns are the same
773
while (it.hasNext() && sameTable) {
774                             Map.Entry JavaDoc me = (Map.Entry JavaDoc) it.next();
775                             String JavaDoc cofn = (String JavaDoc) me.getKey();
776                             String JavaDoc clfn1 = (String JavaDoc) me.getValue();
777                             String JavaDoc clfn2 = (String JavaDoc) proj2.get(cofn);
778                             sameTable = sameColumn(
779                                     je1, clfn1, je2, clfn2, !it.hasNext());
780                         }
781                     } else {
782                         throw new MedorException("Bad PName equality: " +
783                                 "PName structures unknwon or not same");
784                     }
785                     if (sameTable) {
786                         //remove this PName equality
787
return null;
788                     }
789                 }
790             }
791         } else if (e instanceof BinaryLogicalOperator) {
792             // some children of this node can be removed.
793
Operator op = (Operator) e;
794             Expression e0 = removeUseLessPNameEquality(op.getExpression(0));
795             Expression e1 = removeUseLessPNameEquality(op.getExpression(1));
796             if (e0 == null && e1 != null) {
797                 // e0 has been removed ==> return only the other child
798
return e1;
799             } else if (e0 != null && e1 == null) {
800                 // e1 has been removed ==> return only the other child
801
return e0;
802             } else if (e0 == null && e1 == null) {
803                 //Both children has been removed ==> remove the operator
804
return null;
805             } else {
806                 // No children has been removed but they could be changed
807
if (e0 != null && e0 != op.getExpression(0)) {
808                     op.setExpression(0, e0);
809                 }
810                 if (e0 != null && e0 != op.getExpression(0)) {
811                     op.setExpression(0, e0);
812                 }
813                 return op;
814             }
815         } else if (e instanceof Operator) {
816             // Manage operator which are not logical operators.
817
// No removing is authorized in this operator.
818
Operator op = (Operator) e;
819             int size = op.getOperandNumber();
820             for (int i = 0; i < size; i++) {
821                 if (removeUseLessPNameEquality(op.getExpression(i)) == null) {
822                     throw new MedorException(
823                             "Impossible to remove the operand " + i
824                             + " of operator " + e);
825                 }
826             }
827         }
828         // nothing done.
829
return e;
830     }
831
832     /**
833      * Indicates if two field are mapped over the same column, and replaces if
834      * required the use of the external table by the use of other.
835      * <p>If both tables are external then the second is replaced.
836      * Of course the replacement is done
837      * if the column are the same and if the 'replacetable' parameter value is
838      * 'true'.
839      * @param je1 is the extent of the first field.
840      * @param fieldname1 is the field name of the first field.
841      * @param je2 is the extent of the second field.
842      * @param fieldname2 is the field name of the second field.
843      * @param replacetable indicates if the use of the one table must be
844      * replaced by the use of the other.
845      * @return a boolean value indicating if two fields are mapped over the same
846      * column.
847      * @throws MedorException if a problem occurs during the fetching of the
848      * table.
849      */

850     private boolean sameColumn(JormExtent je1,
851                                String JavaDoc fieldname1,
852                                JormExtent je2,
853                                String JavaDoc fieldname2,
854                                boolean replacetable) throws MedorException {
855         RdbPrimitiveElementMapping pem1 =
856                 (RdbPrimitiveElementMapping) getPEM(je1, fieldname1);
857         RdbTable t1 = (RdbTable) pem1.getParent();
858         RdbPrimitiveElementMapping pem2 =
859                 (RdbPrimitiveElementMapping) getPEM(je2, fieldname2);
860         RdbTable t2 = (RdbTable) pem2.getParent();
861         boolean res = t1.getName().equals(t2.getName())
862                 && t1.isColocated()
863                 && t2.isColocated()
864                 && pem1.getName().equals(pem2.getName());
865         if (debug) {
866             log.log(BasicLevel.DEBUG, "Comparing field " + fieldname1 + " to " + fieldname2
867                     + ": result " + res);
868         }
869         if (res && replacetable) {
870             RdbJormExtentMapping rjem1 = getMapping(je1);
871             int idx1 = getTableIndex(rjem1, pem1, unQualifiedName(fieldname1, je1));
872             RdbJormExtentMapping rjem2 = getMapping(je2);
873             int idx2 = getTableIndex(rjem2, pem2, unQualifiedName(fieldname2, je2));
874             if (t1 instanceof RdbExternalTable) {
875                 replaceTable(rjem2, idx2, rjem1, idx1);
876             } else {
877                 replaceTable(rjem1, idx1, rjem2, idx2);
878             }
879         }
880         return res;
881     }
882
883     /**
884      * Replaces the use of a table by another.
885      * @param rjem1 is the mapping of the extent which one table must be replaced
886      * @param idx1 is the index of the table to replace
887      * @param rjem2 is the mapping of the extent which contains the table to use
888      * @param idx2 is the index of the table to use
889      */

890     private void replaceTable(RdbJormExtentMapping rjem1,
891                               int idx1,
892                               RdbJormExtentMapping rjem2,
893                               int idx2) {
894         if (debug) {
895             log.log(BasicLevel.DEBUG, "Replacing table "
896                     + idx1 + " of extent " + mappings.indexOf(rjem1)
897                     + " by table "
898                     + idx2 + " of extent " + mappings.indexOf(rjem2));
899         }
900         QualifiedTable old = (QualifiedTable) rjem1.tables.get(idx1);
901         QualifiedTable neo = (QualifiedTable) rjem2.tables.get(idx2);
902         for (int i = 0; i < mappings.size(); i++) {
903             RdbJormExtentMapping r = (RdbJormExtentMapping) mappings.get(i);
904             for (int j = 0; j < r.tables.size(); j++) {
905                 if (r.tables.get(j) == old) {
906                     r.tables.set(j, neo);
907                 }
908             }
909         }
910     }
911
912     /**
913      * Retrieves the index of the table which is reached with a given join name
914      * @param rjem is the mapping of the JormExtent which the table index is
915      * expected
916      * @param pem is the column which designates the table index expected
917      * @param fieldname is used to known which join must be used
918      * @throws MedorException if no join is found for the column if it was
919      * needed
920      */

921     private int getTableIndex(RdbJormExtentMapping rjem,
922                               RdbPrimitiveElementMapping pem,
923                               String JavaDoc fieldname) throws MedorException {
924         //one table
925
if (rjem.tables.size() == 1 && rjem.joins.get(0) == null) {
926             return 0;
927         }
928         Iterator JavaDoc it = pem.getPrimitiveElementByRdbJoin().entrySet().iterator();
929         if (!it.hasNext())
930             return 0;
931         RdbJoin j = null;
932         while (it.hasNext()) {
933             Map.Entry JavaDoc me = (Map.Entry JavaDoc) it.next();
934             if (((PrimitiveElement) me.getValue()).getName().equals(fieldname)) {
935                 j = (RdbJoin) me.getKey();
936                 break;
937             }
938         }
939         if (j == null) {
940             //field not found in joins
941
throw new MedorException(
942                     "No join found for the mapping of the column '"
943                     + pem.getName() + "'");
944         }
945         return rjem.getJoinIndex(j.getName());
946     }
947
948     /**
949      * Replaces the uses of the old fields of extents by fields of a leaf.
950      * The PNameField uses are replaced by the corresponding equality between
951      * fields of the name(single or composite).
952      * @param e the expression to update
953      * @param leaf is the field containing the new field.
954      * @param add indicates whether the Field should be added (it is projected)
955      * or not (it is only in the Filter).
956      * @return the updated expression (Never null).
957      * @throws MedorException if it is not possible to fetch a new field in the
958      * leaf or if the PName equality are malformed
959      */

960     public Expression updateFieldOfExpression(Expression e,
961                                               BasicRdbExpQueryLeaf leaf,
962                                               boolean add)
963             throws MedorException, ExpressionException {
964         log.log(BasicLevel.DEBUG, "Entering updateFieldOfExpression for " + ExpressionPrinter.e2str(e));
965         if (e == null) {
966             return null;
967         }
968         if ((e instanceof Equal)
969                 || (e instanceof NotEqual)
970                 || (e instanceof MemberOf)) {
971             Operator eq = (Operator) e;
972             Expression left = eq.getExpression(0);
973             Expression right = eq.getExpression(1);
974             if (left instanceof FieldOperand && right instanceof FieldOperand) {
975                 FieldOperand fo1 = (FieldOperand) left;
976                 FieldOperand fo2 = (FieldOperand) right;
977                 QueryTreeField qtf1 = (QueryTreeField) fo1.getField();
978                 QueryTreeField qtf2 = (QueryTreeField) fo2.getField();
979                 if (qtf1 instanceof PNameField && qtf2 instanceof PNameField) {
980                     //This is a PName equality
981

982                     PNameField pnf1 = (PNameField) qtf1;
983                     JormExtent je1 = (JormExtent) pnf1.getQueryTree();
984                     NameDef nd1 = pnf1.getNameDef(je1);
985
986                     PNameField pnf2 = (PNameField) qtf2;
987                     JormExtent je2 = (JormExtent) pnf2.getQueryTree();
988                     NameDef nd2 = pnf2.getNameDef(je2);
989
990                     if (nd1.isFieldName() && nd2.isFieldName()) {
991                         // only the operand must be changed
992
if (debug) {
993                             log.log(BasicLevel.DEBUG, "Replace the PName comparison: "
994                                     + ExpressionPrinter.e2str(e));
995                         }
996                         fo1.setField(getField(nd1.getFieldName(), je1, leaf, add));
997                         fo2.setField(getField(nd2.getFieldName(), je2, leaf, add));
998                         if (debug) {
999                             log.log(BasicLevel.DEBUG, "by the field comparison: "
1000                                    + ExpressionPrinter.e2str(e));
1001                        }
1002                        if (e instanceof MemberOf) {
1003                            mofs.add(e);
1004                            extents.add(je2);
1005                        }
1006                        return e;
1007                    } else if (nd1.isNameRef() && nd2.isNameRef()) {
1008                        if (!nd1.getNameRef().getCompositeName().getFQName()
1009                                .equals(nd2.getNameRef().getCompositeName().getFQName())) {
1010                            throw new MalformedExpressionException("Bad PName " +
1011                                    "equality: two different composite name");
1012                        }
1013                        Map JavaDoc proj1 = nd1.getNameRef().getProjection();
1014                        Map JavaDoc proj2 = nd2.getNameRef().getProjection();
1015                        if (proj1.size() != proj2.size()) {
1016                            throw new MalformedExpressionException(
1017                                    "Bad PName equality: bad projection size");
1018                        }
1019                        //replace the PName equality by the equalities of the
1020
// PName fields
1021
if (debug) {
1022                            log.log(BasicLevel.DEBUG, "Replace the PName comparison: "
1023                                    + ExpressionPrinter.e2str(e));
1024                        }
1025                        Expression res = null;
1026                        Iterator JavaDoc it = proj1.entrySet().iterator();
1027                        ArrayList JavaDoc al1 = null;
1028                        ArrayList JavaDoc al2 = null;
1029                        if (e instanceof MemberOf) {
1030                            al1 = new ArrayList JavaDoc(1);
1031                            al2 = new ArrayList JavaDoc(1);
1032                        }
1033                        while (it.hasNext()) {
1034                            Map.Entry JavaDoc me = (Map.Entry JavaDoc) it.next();
1035                            String JavaDoc cofn = (String JavaDoc) me.getKey();
1036                            String JavaDoc clfn1 = (String JavaDoc) me.getValue();
1037                            String JavaDoc clfn2 = (String JavaDoc) proj2.get(cofn);
1038                            Field f1 = getField(clfn1, je1, leaf, add);
1039                            Field f2 = getField(clfn2, je2, leaf, add);
1040                            if (e instanceof Equal) {
1041                                Equal equal = new Equal(
1042                                        new BasicFieldOperand(f1),
1043                                        new BasicFieldOperand(f2));
1044                                if (debug) {
1045                                    log.log(BasicLevel.DEBUG, "equality: "
1046                                            + ExpressionPrinter.e2str(equal));
1047                                }
1048                                if (res == null) {
1049                                    res = equal;
1050                                } else {
1051                                    res = new And(res, equal);
1052                                }
1053                            } else if (e instanceof NotEqual) {
1054                                NotEqual notequal = new NotEqual(
1055                                        new BasicFieldOperand(f1),
1056                                        new BasicFieldOperand(f2));
1057                                if (debug) {
1058                                    log.log(BasicLevel.DEBUG, "not-equality: "
1059                                            + ExpressionPrinter.e2str(notequal));
1060                                }
1061                                if (res == null) {
1062                                    res = notequal;
1063                                } else {
1064                                    res = new And(res, notequal);
1065                                }
1066                            } else if (e instanceof MemberOf) {
1067                                al1.add(new BasicFieldOperand(f1));
1068                                al2.add(new BasicFieldOperand(f2));
1069                            }
1070                        }
1071                        if (e instanceof MemberOf) {
1072                            MemberOf memberof = new MemberOf(al1, al2);
1073                            if (debug) {
1074                                log.log(BasicLevel.DEBUG, "memberof: "
1075                                        + ExpressionPrinter.e2str(memberof));
1076                            }
1077                            if (res == null) {
1078                                res = memberof;
1079                            } else {
1080                                res = new And(res, memberof);
1081                            }
1082                            if (e instanceof MemberOf) {
1083                                mofs.add(memberof);
1084                                mofExtents.add(je2);
1085                            }
1086                        }
1087                        if (debug) {
1088                            log.log(BasicLevel.DEBUG, "by the fields comparison: "
1089                                    + ExpressionPrinter.e2str(res));
1090                        }
1091                        return res;
1092                    } else {
1093                        throw new MalformedExpressionException("Bad PName " +
1094                                "equality: PName structures unknwon or not same");
1095                    }
1096                }
1097                //not PName fields
1098
else if (e instanceof MemberOf) {
1099                    if (debug) {
1100                        log.log(BasicLevel.DEBUG, "MemberOf on normal fields");
1101                    }
1102                    JormExtent je1 = (JormExtent) qtf1.getQueryTree();
1103                    JormExtent je2 = (JormExtent) qtf2.getQueryTree();
1104                    if (debug) {
1105                        log.log(BasicLevel.DEBUG, "Replace the MemberOf: "
1106                                + ExpressionPrinter.e2str(e));
1107                    }
1108                    ArrayList JavaDoc al1 = new ArrayList JavaDoc(1);
1109                    ArrayList JavaDoc al2 = new ArrayList JavaDoc(1);
1110                    Field f1 = getField(
1111                            qtf1.getName().substring(je1.getName().length() + 1),
1112                            je1, leaf, add);
1113                    Field f2 = getField(
1114                            qtf2.getName().substring(je2.getName().length() + 1),
1115                            je2, leaf, add);
1116                    al1.add(new BasicFieldOperand(f1));
1117                    al2.add(new BasicFieldOperand(f2));
1118                    MemberOf memberof = new MemberOf(al1, al2);
1119
1120                    if (debug) {
1121                        log.log(BasicLevel.DEBUG, "by the field comparison: "
1122                                + ExpressionPrinter.e2str(memberof));
1123                    }
1124                    mofs.add(memberof);
1125                    extents.add(je2);
1126                    return memberof;
1127                }
1128            } else if (left instanceof FieldOperand && right instanceof Operand) {
1129                FieldOperand fo = (FieldOperand) left;
1130                QueryTreeField qtf = (QueryTreeField) fo.getField();
1131                if (qtf instanceof PNameField) {
1132                    return replacePNameOperandEquality(eq, leaf, add);
1133                }
1134            } else if (left instanceof Operand && right instanceof FieldOperand) {
1135                FieldOperand fo = (FieldOperand) right;
1136                QueryTreeField qtf = (QueryTreeField) fo.getField();
1137                if (qtf instanceof PNameField) {
1138                    return replacePNameOperandEquality(eq, leaf, add);
1139                }
1140            }
1141            //TODO for MemberOf add the case of value comparison (not PName)
1142
}
1143
1144        //Not PName equality
1145
if (e instanceof IsEmpty) {
1146            IsEmpty ie = (IsEmpty) e;
1147            FieldOperand fo = (FieldOperand) ie.getExpression(0);
1148            QueryTreeField qtf = (QueryTreeField) fo.getField();
1149            JormExtent je = (JormExtent) qtf.getQueryTree();
1150            String JavaDoc fname;
1151            if (qtf instanceof PNameField) {
1152                PNameField pnf = (PNameField) qtf;
1153                fname = pnf.getNameDef(je).getFieldName();
1154            } else {
1155                fname = qtf.getName().substring(je.getName().length() + 1);
1156            }
1157            fo.setField(getField(fname, je, leaf, add));
1158            empties.add(ie);
1159                } else if (e instanceof Operator) {
1160            Operator op = (Operator) e;
1161            if (debug) {
1162                log.log(BasicLevel.DEBUG, "update the operator: " + op.getOperatorString());
1163            }
1164            int size = op.getOperandNumber();
1165            for (int i = 0; i < size; i++) {
1166                op.setExpression(i,
1167                        updateFieldOfExpression(op.getExpression(i), leaf, add));
1168            }
1169        } else if (e instanceof FieldOperand) {
1170            Field f = ((FieldOperand) e).getField();
1171            if (f instanceof PNameField) {
1172                Expression res = getDecode((PNameField) f, leaf, add);
1173                if (debug) {
1174                    log.log(BasicLevel.DEBUG, "Replace the FieldOperand "
1175                            + f.getName() + " by a decode: "
1176                            + ExpressionPrinter.e2str(res));
1177                }
1178                return res;
1179            } else {
1180                if (debug) {
1181                    log.log(BasicLevel.DEBUG,
1182                            "Update the FieldOperand " + f.getName());
1183                }
1184                ((FieldOperand) e).setField(getField(f, leaf, add));
1185                return e;
1186            }
1187        }
1188        return e;
1189    }
1190
1191    /**
1192     * Create an expression to decode a PName.
1193     * @param pnf is the PNameField linked to JormExtent which is the old
1194     * representation of the PName.
1195     * @param leaf is the leaf which contains the field of the NameDef. It the
1196     * fields do not exist then they are created.
1197     * @return an expression to decode a PName.
1198     * @throws MedorException if the NameDef is not supported or if the a field
1199     * can not be created in the leaf.
1200     */

1201    public Expression getDecode(PNameField pnf,
1202                                BasicRdbExpQueryLeaf leaf,
1203                                boolean add)
1204            throws MedorException {
1205        if (debug) {
1206            log.log(BasicLevel.DEBUG, "(getDecode) Handling PNameField " + pnf.getName());
1207        }
1208        JormExtent extent = (JormExtent) pnf.getQueryTree();
1209        if (debug) {
1210            log.log(BasicLevel.DEBUG, "in extent " + extent.getJormName());
1211        }
1212        Operand o = getPNCOperand(extent, pnf);
1213        PType type = pnf.getType();
1214        log.log(BasicLevel.DEBUG, "Looking for NameDef of " + pnf);
1215        NameDef nd = pnf.getNameDef(extent);
1216        if (nd.isFieldName()) {
1217            return new SinglePName(new BasicFieldOperand(
1218                    getField(nd.getFieldName(), extent, leaf, add)), o, type);
1219        } else if (nd.isNameRef()) {
1220            Map JavaDoc proj = nd.getNameRef().getProjection();
1221            FieldOperand[] fos = new BasicFieldOperand[proj.size()];
1222            String JavaDoc[] cofns = new String JavaDoc[proj.size()];
1223            int counter = 0;
1224            QueryTreeField qtf = null;
1225            for (Iterator JavaDoc it = proj.entrySet().iterator(); it.hasNext();) {
1226                Map.Entry JavaDoc me = (Map.Entry JavaDoc) it.next();
1227                cofns[counter] = (String JavaDoc) me.getKey();
1228                String JavaDoc clafn = (String JavaDoc) me.getValue();
1229                qtf = getField(clafn, extent, leaf, add);
1230                fos[counter] = new BasicFieldOperand(qtf);
1231                counter++;
1232            }
1233            //add a CalculatedField into the intermediate QueryTree.
1234
// This calculatedField has an expression which is a
1235
// CompositePName.
1236
return new CompositePName(fos, cofns, o, type);
1237        }
1238        throw new MedorException("Unsupport namedef: " + nd);
1239    }
1240
1241    /**
1242     * Replaces the equality between a PName and an operand.
1243     * @param e is the Equal, NotEqual or MemberOf object which must have a
1244     * FieldOperand referencing a PNameField and an Operand.
1245     * @param leaf is the leaf containg the new fields composing the PNameField
1246     * @return the new expression comparing PName fields to operands.
1247     * @throws MedorException if the expression is malformed or if it is not
1248     * possible to fetch a new Field on the leaf.
1249     */

1250    private Expression replacePNameOperandEquality(Operator e,
1251                                                   BasicRdbExpQueryLeaf leaf,
1252                                                   boolean add)
1253            throws ExpressionException, MedorException {
1254        if (debug) {
1255            log.log(BasicLevel.DEBUG, "Equality between PName and a parameter");
1256        }
1257        Expression left = e.getExpression(0);
1258        Expression right = e.getExpression(1);
1259        FieldOperand fo = null;
1260        PNameField pnf = null;
1261        Operand o = null;
1262        boolean isLeft = true;
1263        if (left instanceof FieldOperand && right instanceof Operand) {
1264            fo = (FieldOperand) left;
1265            pnf = (PNameField) fo.getField();
1266            o = (Operand) right;
1267            isLeft = false;
1268        } else if (left instanceof Operand && right instanceof FieldOperand) {
1269            fo = (FieldOperand) right;
1270            pnf = (PNameField) fo.getField();
1271            o = (Operand) left;
1272        }
1273        JormExtent je = (JormExtent) pnf.getQueryTree();
1274        if (e instanceof MemberOf) {
1275            mofs.add(e);
1276            extents.add(je);
1277        }
1278        NameDef nd = pnf.getNameDef(je);
1279        VariableOperand newo;
1280        if (nd.isFieldName()) {
1281            Field f = getField(nd.getFieldName(), je, leaf, add);
1282            fo.setField(f);
1283            if (o instanceof ParameterOperand) {
1284                newo = new EncodePName(f.getType(), ((ParameterOperand) o).getName());
1285                e.setExpression((isLeft ? 0 : 1), newo);
1286            } else {
1287                newo = new BasicVariableOperand(f.getType());
1288                try {
1289                    EncodePName.assignEncodedValue((PName) o.getObject(), newo, null);
1290                }
1291                catch (PException ex) {
1292                    throw new MedorException("Impossible to encode PName", ex);
1293                }
1294                if (newo.getObject() == null) {
1295                    //transform to a isNull operator
1296
return new IsNull(fo);
1297                }
1298                e.setExpression((isLeft ? 0 : 1), newo);
1299            }
1300            if (debug) {
1301                log.log(BasicLevel.DEBUG,
1302                        "Equality between PName and a parameter: "
1303                        + ExpressionPrinter.e2str(e));
1304            }
1305            return e;
1306        } else if (nd.isNameRef()) {
1307            Expression res = null;
1308            Map JavaDoc proj1 = nd.getNameRef().getProjection();
1309            Iterator JavaDoc it = proj1.entrySet().iterator();
1310            while (it.hasNext()) {
1311                Map.Entry JavaDoc me = (Map.Entry JavaDoc) it.next();
1312                String JavaDoc cofn = (String JavaDoc) me.getKey();
1313                String JavaDoc clfn = (String JavaDoc) me.getValue();
1314                Field f = getField(clfn, je, leaf, add);
1315                if (o instanceof ParameterOperand) {
1316                    newo = new EncodePName(f.getType(), ((ParameterOperand) o).getName(), cofn);
1317                } else {
1318                    newo = new BasicVariableOperand(f.getType());
1319                    try {
1320                        EncodePName.assignEncodedValue((PName) o.getObject(), newo, cofn);
1321                    }
1322                    catch (PException ex) {
1323                        throw new MedorException("Impossible to encode PName", ex);
1324                    }
1325                }
1326                if (e instanceof Equal) {
1327                    Expression test;
1328                    if (!(o instanceof ParameterOperand) && newo.getObject() == null) {
1329                        //transform to a isNull operator
1330
test = new IsNull(new BasicFieldOperand(f));
1331                    } else {
1332                        test = (isLeft
1333                                ? new Equal(newo, new BasicFieldOperand(f))
1334                                : new Equal(new BasicFieldOperand(f), newo));
1335                    }
1336                    if (res == null) {
1337                        res = test;
1338                    } else {
1339                        res = new And(res, test);
1340                    }
1341                }
1342                if (e instanceof MemberOf) {
1343                    ArrayList JavaDoc al1 = new ArrayList JavaDoc(1);
1344                    al1.add(newo);
1345                    ArrayList JavaDoc al2 = new ArrayList JavaDoc(1);
1346                    al2.add(new BasicFieldOperand(f));
1347                    MemberOf memberof =
1348                            new MemberOf(al1, al2);
1349                    if (res == null) {
1350                        res = memberof;
1351                    } else {
1352                        res = new And(res, memberof);
1353                    }
1354                } else if (e instanceof NotEqual) {
1355                    NotEqual notequal =
1356                            (isLeft
1357                            ? new NotEqual(newo, new BasicFieldOperand(f))
1358                            : new NotEqual(new BasicFieldOperand(f), newo));
1359                    if (res == null) {
1360                        res = notequal;
1361                    } else {
1362                        res = new Or(res, notequal);
1363                    }
1364                }
1365            }
1366            if (debug) {
1367                log.log(BasicLevel.DEBUG,
1368                        "Equality between PName and a parameter: "
1369                        + ExpressionPrinter.e2str(res));
1370            }
1371            return res;
1372        } else {
1373            throw new MalformedExpressionException("Bad PName " +
1374                    "equality: PName structures unknwon or not same");
1375        }
1376    }
1377
1378    /**
1379     * Is a shorcut to the
1380     * getField(String, PType, JormExtent, BasicRdbExpQueryLeaf, boolean)
1381     * method.
1382     * <p>The fieldname, the type and the extent values are calculated from the
1383     * old Field.
1384     * @param old the old field
1385     * @throws MedorException if an error occurs during the real getField call.
1386     */

1387    public QueryTreeField getField(Field old,
1388                                   BasicRdbExpQueryLeaf leaf,
1389                                   boolean add)
1390            throws MedorException {
1391        Field f = old;
1392        if (f instanceof PropagatedField) {
1393            f = ((PropagatedField) f).getPreviousFields()[0];
1394        }
1395        QueryTree qt = ((QueryTreeField) f).getQueryTree();
1396        if (qt == leaf) {
1397            return (QueryTreeField) f;
1398        } else if (qt instanceof JormExtent) {
1399            return getField(
1400                    f.getName(), f.getType(), (JormExtent) qt, leaf, add);
1401        } else {
1402            throw new MedorException("Impossible to fetch the new field " +
1403                    "corresponding to the old field: " + f.getName()
1404                    + " : the query tree is not a JormExtent: " + qt);
1405        }
1406    }
1407
1408    /**
1409     * Shortcut to the
1410     * getField(String, PType, JormExtent, BasicRdbExpQueryLeaf, boolean)
1411     * method.
1412     * <p>The field type is calculated looking for the field in the JORM meta
1413     * information.
1414     * @throws MedorException if the field is not found in the JORM meta
1415     * information or if an error occurs during the real getField call.
1416     */

1417    public QueryTreeField getField(String JavaDoc fieldname,
1418                                   JormExtent extent,
1419                                   BasicRdbExpQueryLeaf leaf,
1420                                   boolean add)
1421            throws MedorException {
1422        if (debug) {
1423            log.log(BasicLevel.DEBUG, "(getField-4) Handling field " + fieldname);
1424        }
1425        return getField(fieldname,
1426                        getPrimitiveElement(extent, fieldname).getType(),
1427                        extent,
1428                        leaf,
1429                        add);
1430    }
1431
1432    /**
1433     * Adds a field in a leaf if it is not already present.
1434     * @param fieldname is the field name of the expected field.
1435     * @param type is the jorm type of expected field.
1436     * @param extent is the extent containing the old version of the expected
1437     * field.
1438     * @param leaf is the leaf which must contain the expected field after the
1439     * the method call
1440     * @param add indicates whether the field should be added to the leaf
1441     * @return the expected field
1442     * @throws MedorException if no old field is not available on the extent
1443     * or if no mapping is available for the field.
1444     */

1445    public QueryTreeField getField(String JavaDoc fieldname,
1446                                   PType type,
1447                                   JormExtent extent,
1448                                   BasicRdbExpQueryLeaf leaf,
1449                                   boolean add)
1450            throws MedorException {
1451        String JavaDoc fqfn = qualifiedName(fieldname, extent);
1452        if (debug) {
1453            log.log(BasicLevel.DEBUG, "(getField-5) Handling field " + fieldname + " (full name: " + fqfn + ")");
1454            Field[] leafFields = leaf.getTupleStructure().getFields();
1455            if (leafFields.length == 0) {
1456                log.log(BasicLevel.DEBUG, "Leaf has no fields");
1457            }
1458            for (int jj=0; jj<leafFields.length; jj++) {
1459                log.log(BasicLevel.DEBUG, "Leaf has field " + leafFields[jj].getName());
1460            }
1461        }
1462        if (leaf.contains(fqfn)) {
1463            //The field already exists then return it
1464
if (debug) {
1465                log.log(BasicLevel.DEBUG,
1466                        "getField:"
1467                        + " / field: " + fqfn
1468                        + " / type: " + type.getJormName()
1469                        + " already exists");
1470            }
1471            return (QueryTreeField) leaf.getField(fqfn);
1472        }
1473        RdbPrimitiveElementMapping pem =
1474                (RdbPrimitiveElementMapping) getPEM(extent, fieldname);
1475        RdbJormExtentMapping rjem = getMapping(extent);
1476        int idx = getTableIndex(rjem, pem, unQualifiedName(fieldname, extent));
1477        if (debug) {
1478            log.log(BasicLevel.DEBUG,
1479                    "getField:"
1480                    + " / field: " + fqfn
1481                    + " / type: " + type.getJormName()
1482                    + " / pem: " + pem.getName()
1483                    + " / rjem: " + rjem.extent.getJormName()
1484                    + " / table: "
1485                    + ((QualifiedTable) rjem.tables.get(idx)).getAliasName());
1486        }
1487        getTable(rjem, idx, leaf, false);
1488        String JavaDoc colName = pem.getName();
1489        //if the class is polymorphic, put the pe.getName instead of the pem.getName
1490
if (((QualifiedTable) rjem.tables.get(idx)).isPolymorphic()) {
1491            //the field name is used instead of the sql column name
1492
colName = getJORMFieldName(fieldname, extent);
1493        }
1494        RdbExpField res = leaf.addRdbField(
1495                fqfn,
1496                type, colName,
1497                (QualifiedTable) rjem.tables.get(idx));
1498        if (!add) {
1499            leaf.removeRdbField(res);
1500        }
1501        return res;
1502    }
1503
1504    /**
1505     * It adds (if it is not already present) a QualifiedTable instance into a
1506     * leaf. The joins are automatically added in the global variable 'filter'.
1507     * @param rjem is the jorm extent mapping containg the expected table
1508     * @param idx is the index of the table into the list of tables of the
1509     * JORM extent mapping rjem
1510     * @param leaf is the BasicRdbExpQueryLeaf which must contain the expected
1511     * qualified table after the call to this method.
1512     * @throws MedorException if an exception occurs during the addition of
1513     * join between table.
1514     */

1515    private void getTable(RdbJormExtentMapping rjem,
1516                          int idx,
1517                          BasicRdbExpQueryLeaf leaf,
1518                          boolean add) throws MedorException {
1519        //TODO it seems that "add" is always false. Only used by addJoin which is private. Check and remove.
1520
QualifiedTable qt = (QualifiedTable) rjem.tables.get(idx);
1521        if (debug) {
1522            log.log(BasicLevel.DEBUG, "Looking for the table " + qt.getAliasName());
1523        }
1524        if (leaf.containsQualifiedTable(qt))
1525            return;
1526        if (idx != 0) {
1527            //The external table must be added to the leaf
1528
getTable(rjem, 0, leaf, add);
1529            if (debug) {
1530                log.log(BasicLevel.DEBUG, "Add the external table " + qt.getAliasName());
1531            }
1532            leaf.addQualifiedTable(qt);
1533            addJoin(rjem, idx, leaf, add);
1534        } else {
1535            //The main table must be added to the leaf
1536
if (debug) {
1537                log.log(BasicLevel.DEBUG, "Add the main table " + qt.getAliasName());
1538            }
1539            leaf.addQualifiedTable(qt);
1540            //looking if this table is used as external table by other extent
1541
boolean unused = true;
1542            for (int i = 0; i < mappings.size(); i++) {
1543                RdbJormExtentMapping m = (RdbJormExtentMapping) mappings.get(i);
1544                //don't consider the first table which is a main table.
1545
int jdx = 1;
1546                int size = m.tables.size();
1547                while (jdx < size && m.tables.get(jdx) != qt) {
1548                    jdx++;
1549                }
1550                if (jdx < size) {
1551                    unused = false;
1552                    // Add the main table of the extent which uses the expected
1553
// main table
1554
getTable(m, 0, leaf, add);
1555                    //Of course add the join
1556
addJoin(m, jdx, leaf, add);
1557                }
1558            }
1559            if (unused && !joinedTables.contains(qt)) {
1560                joinedTables.add(qt);
1561            }
1562        }
1563    }
1564
1565    /**
1566     * Adds a join expression into the global variable 'filter". The join is
1567     * between an axternal table and the main table of a jorm extent mapping.
1568     * @param rjem is the jorm extent mapping containing the tables to join
1569     * @param idx is the index of the external table in the table list of the
1570     * jorm extent mapping
1571     * @param leaf is the leaf hosting the field of the join.
1572     * @throws MedorException if an error occurs during the fetching of join
1573     * field.
1574     */

1575    private void addJoin(RdbJormExtentMapping rjem,
1576                         int idx,
1577                         BasicRdbExpQueryLeaf leaf,
1578                         boolean add) throws MedorException {
1579        BasicQualifiedTable qt = (BasicQualifiedTable) rjem.tables.get(idx);
1580        JoinedTable.Join jtj = ((JoinedTable)
1581                rjem.tables.get(0)).createChildren(qt, rjem.outer);
1582        Join j = (Join) rjem.joins.get(idx);
1583        RdbExpField f2;
1584        for (int i = 0; i < j.columns.length; i++) {
1585            JoinColumn jc = j.columns[i];
1586            if (jc.field2 == null) {
1587                //create a dummy field in the leaf
1588
f2 = leaf.addRdbField(jc.column2, jc.type, jc.column2, qt);
1589            } else {
1590                f2 = (RdbExpField) getField(jc.field2, rjem.extent, leaf, add);
1591            }
1592            RdbField f1 = (RdbField) getField(jc.field1, rjem.extent, leaf, add);
1593            jtj.addJoinColumn(f1.getColumnName(), f2.getColumnName());
1594            if (!add) {
1595                leaf.removeRdbField(f2);
1596            }
1597        }
1598    }
1599
1600    private String JavaDoc qualifiedName(String JavaDoc fieldname, JormExtent extent) {
1601        if (fieldname.indexOf(extent.getName() + ".") == -1) {
1602            return extent.getName() + "." + fieldname;
1603        } else
1604            return fieldname;
1605    }
1606
1607    private String JavaDoc unQualifiedName(String JavaDoc fieldname, JormExtent extent) {
1608        int idx = fieldname.indexOf(extent.getName() + ".");
1609        if (idx == -1) {
1610            if (debug) {
1611                log.log(BasicLevel.DEBUG, "Field name " + fieldname + " is already unqualified.");
1612            }
1613            return fieldname;
1614        } else if (idx == 0) {
1615            if (debug) {
1616                log.log(BasicLevel.DEBUG, "Unqualified name of field named " + fieldname + " is " + extent.getName().length() + 1);
1617            }
1618            return fieldname.substring(extent.getName().length() + 1);
1619        } else {
1620            if (debug) {
1621                log.log(BasicLevel.WARN, "Problem to unqualify field named " + fieldname);
1622            }
1623            return null;
1624        }
1625    }
1626
1627    /**
1628     * For a given QueryLeaf, splits the leaf and adds subleaves if there is
1629     * a MemberOf or IsEmpty in the filter.
1630     * @param leaf The Queryleaf to be split
1631     * @param filter The Expression attached to the QueryLeaf
1632     * @throws MedorException
1633     */

1634    private void splitLeaf(RdbExpQueryLeaf leaf, Expression filter) throws MedorException {
1635        //build new query leaves with the mof2extent
1636
if (debug) {
1637            log.log(BasicLevel.DEBUG, "Creating subleaves for filter " + ExpressionPrinter.e2str(filter));
1638        }
1639        for (int i = 0; i < mofs.size(); i++) {
1640            MemberOf mo = (MemberOf) mofs.get(i);
1641            int moSize = mo.getOperandNumber() / 2;
1642            //iterate on all pairs of Fields
1643
if (debug) {
1644                for (int f = 0; f < moSize; f++) {
1645                    log.log(BasicLevel.DEBUG, "- left is "
1646                        + ExpressionPrinter.e2str(mo.getExpression(f)));
1647                }
1648            }
1649            for (int f = 0; f < moSize; f++) {
1650                RdbExpField fRight = (RdbExpField)
1651                    ((FieldOperand) mo.getExpression(f + moSize)).getField();
1652                if (debug) {
1653                    log.log(BasicLevel.DEBUG, "- right field is " + fRight.getName());
1654                }
1655                splitLeaf(leaf, fRight);
1656            }
1657        }
1658        for (int i = 0; i < empties.size(); i++) {
1659            IsEmpty ie = (IsEmpty) empties.get(i);
1660            FieldOperand fo = (FieldOperand) ie.getExpression();
1661            RdbExpField field = (RdbExpField) fo.getField();
1662            splitLeaf(leaf, field);
1663        }
1664    }
1665
1666    private void splitLeaf(RdbExpQueryLeaf leaf, RdbExpField field) throws MedorException {
1667        //create new RdbExpQueryLeaf
1668
//remove the right QTable from main leaf if it is in it
1669
if (leaf.containsQualifiedTable(field.getTable())) {
1670            if (debug) {
1671                log.log(BasicLevel.DEBUG, "- split table is " + field.getTable().getTableName() +
1672                    " (alias " + field.getTable().getAliasName() + ")");
1673                QualifiedTable[] qtstmp = leaf.getQualifiedTables();
1674                log.log(BasicLevel.DEBUG, "- before remove: " + qtstmp.length);
1675                log.log(BasicLevel.DEBUG, "-- leaf " + leaf);
1676                log.log(BasicLevel.DEBUG, "-- qt " + field.getQueryTree());
1677                for (int ii = 0; ii < qtstmp.length; ii++) {
1678                    log.log(BasicLevel.DEBUG, "--- table " + qtstmp[ii].getTableName());
1679                }
1680            }
1681            RdbExpQueryLeaf newLeaf = new BasicRdbExpQueryLeaf(leaf.getDataStore(), "");
1682            subLeaves.add(newLeaf);
1683            //TODO replace the code below with moving all tables of the extent
1684
leaf.removeQualifiedTable(field.getTable());
1685            //OK
1686
newLeaf.addQualifiedTable(field.getTable());
1687            newLeaf.addRdbField(field);
1688            field.setQueryLeaf(newLeaf);
1689            //end OK
1690
if (debug) {
1691                QualifiedTable[] qtstmp = leaf.getQualifiedTables();
1692                log.log(BasicLevel.DEBUG, "- after remove: " + qtstmp.length);
1693                for (int ii = 0; ii < qtstmp.length; ii++) {
1694                    log.log(BasicLevel.DEBUG, "-- table " + qtstmp[ii].getTableName());
1695                }
1696            }
1697        } else {
1698            if (debug) {
1699                log.log(BasicLevel.DEBUG, "- split table already moved");
1700            }
1701            //find the subleaf containing the table
1702
RdbExpQueryLeaf rightLeaf = subleafOfFieldOperand(field);
1703            if (rightLeaf == null) //this should never happen :-)
1704
throw new NullPointerException JavaDoc("Should have found the leaf corresponding to field " + field);
1705            rightLeaf.addRdbField(field);
1706            field.setQueryLeaf(rightLeaf);
1707        }
1708        if (joinedTables.contains(field.getTable())) {
1709            if (debug) {
1710                log.log(BasicLevel.DEBUG, "************Removing the joined table " +
1711                    field.getTable().getTableName() + ".");
1712            }
1713            joinedTables.remove(field.getTable());
1714        }
1715    }
1716
1717    /**
1718     * Scans the filter and moves expressions to subleaves in case of a
1719     * MemberOf or IsEmpty.
1720     * <p>The real work is done by the recursive method tagFilterForMove
1721     * @param filter The query filter of the newly created QueryLeaf
1722     * @param leaf The "root" QueryLeaf
1723     * @return an updated Expression for the root QueryLeaf.
1724     */

1725    private Expression updateFilterWithNewLeaves(Expression filter,
1726                                                 RdbExpQueryLeaf leaf) {
1727        if (debug) {
1728            log.log(BasicLevel.DEBUG, "Moving part of the filter " + ExpressionPrinter.e2str(filter));
1729        }
1730        ToBeMovedToLeaf tbm = tagFilterForMove(filter, leaf);
1731        if (debug) {
1732            log.log(BasicLevel.DEBUG, "Final filter for leaf: " + ExpressionPrinter.e2str(tbm.e));
1733        }
1734        if (tbm.isModified) {
1735            //the expression should be moved to the leaf
1736
tbm.leaf.setQueryFilter(tbm.e);
1737            return null;
1738        } else {
1739            return tbm.e;
1740        }
1741    }
1742
1743    /**
1744     * Recursively parses a filter for moving parts of the filter to sub-
1745     * query leaves in the case of MemberOf.
1746     * <p>Comparisons between fieldsOperands of a Field which is in a subleaf
1747     * are moved to that subleaf. The actual move is potentially performed by
1748     * the upper node in the filter (namely in the case of a "Not").
1749     * @param filter The portion of the filter to be tested.
1750     * @param leaf The root query leaf.
1751     * @return a ToBeMovedToLeaf object, where "isModified" is true if the
1752     * expression "e" should be moved to leaf "leaf".
1753     */

1754    private ToBeMovedToLeaf tagFilterForMove(Expression filter,
1755                                             RdbExpQueryLeaf leaf) {
1756        if (filter instanceof Not) {
1757            ToBeMovedToLeaf me =
1758                    tagFilterForMove(((Not) filter).getExpression(), leaf);
1759            if (me.isModified) {
1760                //the expression should be moved to the leaf
1761
Expression newFilter = null;
1762                if (leaf.getQueryFilter() == null) {
1763                    newFilter = new Not(me.e);
1764                } else {
1765                    newFilter = new And(leaf.getQueryFilter(), new Not(me.e));
1766                }
1767                me.leaf.setQueryFilter(newFilter);
1768                me.isModified = false;
1769                me.e = null;
1770                return me;
1771            }
1772        } else if (filter instanceof And) {
1773            if (debug) {
1774                log.log(BasicLevel.DEBUG, "Found AND " +
1775                        ExpressionPrinter.e2str(filter));
1776                log.log(BasicLevel.DEBUG, "Left side of AND: "
1777                        + ExpressionPrinter.e2str(((And) filter).getExpression(0)));
1778            }
1779            ToBeMovedToLeaf mleft = tagFilterForMove(((And) filter).getExpression(0), leaf);
1780            boolean leftMoved = false;
1781            boolean rightMoved = false;
1782            if (mleft.isModified) {
1783                //the expression should be moved to the leaf
1784
if (debug) {
1785                    log.log(BasicLevel.DEBUG, "Moving left side to leaf "
1786                            + ExpressionPrinter.e2str(mleft.e));
1787                }
1788                leftMoved = true;
1789                mleft.leaf.setQueryFilter(
1790                        ((mleft.leaf.getQueryFilter() == null)
1791                        ? mleft.e
1792                        : new And(
1793                                mleft.leaf.getQueryFilter(),
1794                                mleft.e)
1795                        )
1796                );
1797                if (debug) {
1798                    log.log(BasicLevel.DEBUG, "Filter for leaf "
1799                            + mleft.leaf + " after moving left side is "
1800                            + ExpressionPrinter.e2str(mleft.leaf.getQueryFilter()));
1801                }
1802            }
1803            if (debug) {
1804                log.log(BasicLevel.DEBUG, "Right side of AND: "
1805                        + ExpressionPrinter.e2str(((And) filter).getExpression(1)));
1806            }
1807            ToBeMovedToLeaf mright = tagFilterForMove(((And) filter).getExpression(1), leaf);
1808            if (mright.isModified) {
1809                if (debug) {
1810                    log.log(BasicLevel.DEBUG, "Moving right side to leaf "
1811                            + ExpressionPrinter.e2str(mright.e));
1812                }
1813                rightMoved = true;
1814                mright.leaf.setQueryFilter(
1815                        (mright.leaf.getQueryFilter() == null
1816                        ? mright.e
1817                        : new And(
1818                                mright.leaf.getQueryFilter(),
1819                                mright.e)
1820                        )
1821                );
1822                if (debug) {
1823                    log.log(BasicLevel.DEBUG, "Filter for leaf "
1824                            + mright.leaf + " after moving right side is "
1825                            + ExpressionPrinter.e2str(mright.leaf.getQueryFilter()));
1826                }
1827            }
1828            if (leftMoved) {
1829                if (rightMoved) {
1830                    //left and right already moved
1831
mleft.clear();
1832                    if (debug) {
1833                        log.log(BasicLevel.DEBUG, "All moved: returning empty "
1834                                + ExpressionPrinter.e2str(mleft.e));
1835                    }
1836                    return mleft;
1837                } else {
1838                    //only left already moved
1839
if (debug) {
1840                        log.log(BasicLevel.DEBUG, "Left moved: returning right "
1841                                + ExpressionPrinter.e2str(mright.e));
1842                    }
1843                    return mright;
1844                }
1845            } else {
1846                if (rightMoved) {
1847                    //only right already moved
1848
if (debug) {
1849                        log.log(BasicLevel.DEBUG, "Right moved: returning left "
1850                                + ExpressionPrinter.e2str(mleft.e));
1851                    }
1852                    return mleft;
1853                } else {
1854                    //nothing moved but could be modified
1855
Expression modifAnd =
1856                            new And(mleft.e, mright.e);
1857                    if (debug) {
1858                        log.log(BasicLevel.DEBUG, "None moved: returning modified expression "
1859                                + ExpressionPrinter.e2str(modifAnd));
1860                    }
1861                    return new ToBeMovedToLeaf(modifAnd, false, null);
1862                }
1863            }
1864        }
1865        //TODO add treatment of OR
1866
else if (filter instanceof Comparator) {
1867            //get the two operands
1868
Expression left = ((Comparator) filter).getExpression(0);
1869            Expression right = ((Comparator) filter).getExpression(1);
1870            if (left instanceof FieldOperand) {
1871                //checks if the FieldOperand is for one of the subleaves
1872
RdbExpQueryLeaf subleaf =
1873                        subleafOfFieldOperand((FieldOperand) left);
1874                if (subleaf != null) {
1875                    //mark the subexpression to be moved
1876
return new ToBeMovedToLeaf(filter, true, subleaf);
1877                }
1878            }
1879            if (right instanceof FieldOperand) {
1880                //checks if the FieldOperand is for one of the subleaves
1881
RdbExpQueryLeaf subleaf =
1882                        subleafOfFieldOperand((FieldOperand) right);
1883                if (subleaf != null) {
1884                    //mark the subexpression to be moved
1885
return new ToBeMovedToLeaf(filter, true, subleaf);
1886                }
1887            }
1888            //TODO add treatment for arithmetic operators
1889
}
1890        //otherwise, nothing is moved
1891
return new ToBeMovedToLeaf(filter, false, null);
1892    }
1893
1894    /**
1895     * Returns, if it exists, the subleaf in which a given FieldOperand appears.
1896     * @param fo The FieldOperand to be looked for.
1897     * @return the subleaf in which the FieldOperand appears, if it exists.
1898     * Otherwise, return null.
1899     */

1900    private RdbExpQueryLeaf subleafOfFieldOperand(FieldOperand fo) {
1901        return subleafOfFieldOperand(fo.getField());
1902    }
1903    
1904    private RdbExpQueryLeaf subleafOfFieldOperand(Field f) {
1905        QualifiedTable qtab = ((RdbExpField) f).getTable();
1906        for (int i = 0; i < subLeaves.size(); i++) {
1907            RdbExpQueryLeaf subleaf =
1908                    (RdbExpQueryLeaf) subLeaves.get(i);
1909            QualifiedTable[] tables = subleaf.getQualifiedTables();
1910            if (tables == null) { return null; }
1911            for (int j = 0; j < tables.length; j++) {
1912                if (qtab == tables[j]) {
1913                    if (debug) {
1914                        log.log(BasicLevel.DEBUG, "Found table " + qtab.getTableName() + " in leaf " + subleaf);
1915                    }
1916                    return subleaf;
1917                }
1918            }
1919        }
1920        return null;
1921    }
1922
1923    /**
1924     * In the case the parent node is a Nest, checks whether it contains a
1925     * Count expression on the input QueryTreeField
1926     * @param f The QueryTreeField to be checked whether it is included in a
1927     * Count in the parent QueryNode
1928     * @param parent The parent QueryNode
1929     * @return the Count expression counting QueryTreeField f, if any. Null
1930     * otherwise.
1931     */

1932    private Count fieldUsedInCount(QueryTreeField f, QueryNode parent) {
1933        log.log(BasicLevel.DEBUG, "Entering fieldUsedInCount for " + f + "( " + f.getName() + ")");
1934        if (parent instanceof Nest) {
1935            log.log(BasicLevel.DEBUG, "Parent node is a Nest");
1936            Field[] pfs = parent.getTupleStructure().getFields();
1937            for (int i = 0; i < pfs.length; i++) {
1938                Field fi = pfs[i];
1939                log.log(BasicLevel.DEBUG, "Examining field " + fi + " (" + fi.getName() + ")");
1940                if (fi instanceof CalculatedField) {
1941                    Expression fiExp = ((CalculatedField) fi).getExpression();
1942                    if (fiExp instanceof Count) {
1943                        Field countedField =
1944                            ((PropagatedField)
1945                                ((FieldOperand)
1946                                    ((Count) fiExp).getExpression()).getField())
1947                            .getPreviousFields()[0];
1948                        log.log(BasicLevel.DEBUG, "Counted field " + countedField);
1949                        if (countedField.equals(f)) {
1950                            log.log(BasicLevel.DEBUG, "Field " + f.getName() + " used in Count");
1951                            return (Count) fiExp;
1952                        }
1953                    }
1954                }
1955            }
1956        }
1957        return null;
1958    }
1959
1960    /**
1961     * Extends ModifiedExpression for moving part of a filter to the subleaves.
1962     * <p>Note that isModified has a different meaning here: it means that
1963     * the Expression should be moved to the leaf.
1964     */

1965    private class ToBeMovedToLeaf extends ModifiedExpression {
1966        /**
1967         * The RdbExpQueryLeaf to which the filter portion should be moved.
1968         */

1969        RdbExpQueryLeaf leaf;
1970
1971        ToBeMovedToLeaf(Expression exp, boolean ism, RdbExpQueryLeaf leaf) {
1972            super(exp, ism);
1973            this.leaf = leaf;
1974        }
1975
1976        public void clear() {
1977            e = null;
1978            leaf = null;
1979            isModified = false;
1980        }
1981    }
1982}
1983
Popular Tags