KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > daffodilwoods > daffodildb > server > sql99 > dql > tableexpression


1 package com.daffodilwoods.daffodildb.server.sql99.dql.tableexpression;
2
3 import java.util.*;
4
5 import com.daffodilwoods.daffodildb.server.serversystem.*;
6 import com.daffodilwoods.daffodildb.server.sql99.common.*;
7 import com.daffodilwoods.daffodildb.server.sql99.dql.common.*;
8 import com.daffodilwoods.daffodildb.server.sql99.dql.execution.*;
9 import com.daffodilwoods.daffodildb.server.sql99.dql.listenerevents.*;
10 import com.daffodilwoods.daffodildb.server.sql99.dql.plan.*;
11 import com.daffodilwoods.daffodildb.server.sql99.dql.plan.condition.*;
12 import com.daffodilwoods.daffodildb.server.sql99.dql.plan.order.*;
13 import com.daffodilwoods.daffodildb.server.sql99.dql.plan.table.*;
14 import com.daffodilwoods.daffodildb.server.sql99.dql.tableexpression.fromclause.*;
15 import com.daffodilwoods.daffodildb.server.sql99.dql.tableexpression.groupbyclause.*;
16 import com.daffodilwoods.daffodildb.server.sql99.dql.tableexpression.havingclause.*;
17 import com.daffodilwoods.daffodildb.server.sql99.dql.tableexpression.whereclause.*;
18 import com.daffodilwoods.daffodildb.server.sql99.expression.booleanvalueexpression.*;
19 import com.daffodilwoods.daffodildb.server.sql99.utils.*;
20 import com.daffodilwoods.database.resource.*;
21 import com.daffodilwoods.database.sqlinitiator.*;
22 import com.daffodilwoods.database.utility.P;
23
24 /**
25  * tableexpression represents from,where,group and having clause of a
26  * select query. Only from clause is mandatary and remaining all are optional.
27  * This class provides the functionality of semantic checking and Execution Plan.
28  * It also provides all the information regarding from,where,group and having
29  * clause.
30  * <p>Title: </p>
31  * <p>Description: </p>
32  * <p>Copyright: Copyright (c) 2003</p>
33  * <p>Company: </p>
34  * @author unascribed
35  * @version 1.0
36  */

37
38 public class tableexpression extends JoinRelationAbstract implements com.daffodilwoods.daffodildb.utils.parser.StatementExecuter, TypeConstants, TableExpressionConstants, SimpleConstants {
39
40    /**
41     * Represents having clause of select query. It is optional
42     */

43
44    public havingclause _Opthavingclause0;
45
46    /**
47     * Represents group by clause of select query. It is optional
48     */

49
50    public groupbyclause _Optgroupbyclause1;
51
52    /**
53     * Represents where clause of select query. It is optional
54     */

55
56    public whereclause _Optwhereclause2;
57
58    /**
59     * Represents from clause of select query.
60     */

61
62    public fromclause _fromclause3;
63
64    /**
65     * Represents array of table plans.
66     */

67
68    private _TablePlan[] tablePlans;
69
70    /**
71     * Represents the plan of condition represented by from,where and having
72     * clauses.
73     */

74
75    private _BVEPlan resultantBvePlan;
76
77    /**
78     * Represents the mapping of Table, single table plan and execution plan of
79     * table.
80     */

81
82    private Object JavaDoc[][] tableAndQualifiedPlan; // It contains at poistion [][0] ->> TableDetail , [][1] ->> SingleTablePlan , [][2] ->> QualifiedPlan(ExecutionPlan)
83

84    /**
85     * Represents the plan of order.
86     */

87
88    private _OrderPlan orderPlan;
89
90    /**
91     * Represents the final table plan of this tableexpression.
92     */

93
94    private _TablePlan finalTablePlan;
95
96    /**
97     * Represents the remaining condition which will be solved at the top of
98     * the plan represented by this tableexpression.
99     */

100
101    private booleanvalueexpression remainingCondition;
102
103    /**
104     * Represents the tables involved in from clause.
105     */

106
107    private TableDetails[] tableDetails;
108
109    /**
110     * Represents the tables involved in from clause. It is different from
111     * tableDetails in the way if view is present, then it represents all the
112     * tables involved in view, whereas tableDetails represents the view as table.
113     */

114
115    private TableDetails[] allTableDetails;
116
117    _QueryColumns queryColumns0;
118
119    public tableexpression() {
120    }
121
122    public Object JavaDoc run(Object JavaDoc object) throws com.daffodilwoods.database.resource.DException {
123       throw new DException("DSE16", new Object JavaDoc[] {"run"});
124    }
125
126    /**
127     * It is used to merge two arrays in to one.
128     * @param param1
129     * @param param2
130     * @return
131     */

132
133    private Object JavaDoc[] addParameters(Object JavaDoc[] param1, Object JavaDoc[] param2) {
134       return param1 == null ? param2 : param2 == null ? param1 : mergeParameters(param1, param2);
135    }
136
137    private Object JavaDoc[] mergeParameters(Object JavaDoc[] param1, Object JavaDoc[] param2) {
138       int len1 = param1.length;
139       int len2 = param2.length;
140       int len = len1 + len2;
141       Object JavaDoc[] result = new Object JavaDoc[len];
142       System.arraycopy(param1, 0, result, 0, len1);
143       System.arraycopy(param2, 0, result, len1, len2);
144       return result;
145    }
146
147    /**
148     * It allows user to obtain the combined plan of passed condition and the
149     * condition represented by where clause.
150     * @param condition
151     * @return
152     * @throws DException
153     */

154
155    private _BVEPlan mergeBvePlan(booleanvalueexpression condition) throws DException {
156       _BVEPlan bvePlan = null;
157       if (condition != null) {
158          bvePlan = condition.getExecutionPlan();
159       }
160       if (_Optwhereclause2 != null) {
161          _BVEPlan whereBvePlan = _Optwhereclause2.getExecutionPlan();
162          bvePlan = BVEPlanMerger.mergeTablePlansWithAnd(bvePlan, whereBvePlan);
163       }
164       return bvePlan;
165    }
166
167    /**
168     * This method allows user to obtain a plan through the help of which user
169     * can obtain the resultset. This method firstly makes a plan for condition
170     * with the help of passed condition and the condition present in from, where
171     * and having clauses. After that plan for sorting needs of query is formed
172     * with the help of passed order and order needed for group by clause. And
173     * then plan of 'from clause' is obtained with the help of condition and
174     * order plan. In this step, single table conditions and single table orders
175     * are shifted to single table. After that join conditions are merged among
176     * the plans obtained from 'from clause'. And finally a single plan is formed
177     * for all the table plans obtained from 'from clause'.
178     *
179     * Detailed Description is given below.
180     *
181     * DaffodilDB chooses an execution plan based on the access paths available and assigns
182     * a rank to these paths. DaffodilDB always chooses the path with the lower rank over one with the higher rank
183     * Method is used to get an Plan which can provide us an Iterator.
184     * The Plan which we recieve from the tableexpression class has order and condition merged , ConditionArray and QueryColumns
185     * the method with all this arguments is invoked from the tableorQueryname class
186     * In this method We take all the Plans from the FromClause and Merges All The single Level Conditions from the BVEPlan ,
187     * in these Plans and then we take the OrderPlan From groupBy and OrderBy and merges
188     * them . After that we check whether OrderSeqencePlan is possible for the singleTableLevel Orders and
189     * depending on the possiblity of OrderSequencePlan we change the tablePlan Array . After we merge the JoinRelations
190     * in this tablePlans Array.
191     * Finally the JoinMissingLink make a final TablePlan.
192     * @param session
193     * @param bve --> singleLevel condition of View
194     * @param datedFrameWork
195     * @param queryColumns --> Columns involved in the Query[Used to calculate the cost at singleTablePlan]
196     * @param order0 --> SingleTableOrder of the
197     * @param conditionArray --> ConditionArray contains the condition related to this Query ,
198     * it will be null if it is root level Query , in case of View it Will contain the
199     * SingleLevel Condition of the View.
200     *--------------------------
201     *REQUIREMENT OF ARGUMENTS |
202     *--------------------------
203     *Condition >> This are SingleLevel Conditions of View .
204     * For the above view we would like to shift the condition V.Id = 1 to the Orders Table as V.Id column is
205     * actually of Orders.OrderId .Since in this tableExpression/querySpecification we are having the tablePlan
206     * of Orders so we need to pass the information upto this level.
207     *ViewOrder >> This are SingleLevel Conditions of View .
208     * For the above view we would like to shift the order on column V.Id to the Orders Table as V.Id column is
209     * actually of Orders.OrderId .Since in this tableExpression/querySpecification we are having the tablePlan
210     * of Orders so we need to pass the information to this level.
211     *QueryColumns >> QueryColumns helps to calculate the cost of Plan Generated.As it tells the columns involved in the
212     * Query.There is always a cost of extracting any column from the Database.This cost calculation work
213     * is done at SingleTablePlan.
214     *ConditionArray >> For Changing the type of joins beacuse of the condition present in where clause or on clause
215     * we need to pass the these conditions as they can change their meaning
216     * for eg Select * from Orders left Outer Join "Order Details" on Orders.OrderId = 11111 where "Orders Details".OrderId > 1
217     * This Query will act as Select * from Orders , "Order Details" where "Orders Details".OrderId > 1 and Orders.OrderId = 11111
218     * We need to pass "Orders Details".OrderId > 1 information to qualifiedJoin of Orders left Outer Join "Order Details"
219     * so that it can change treat as simple Join.
220     * We could have passed TableDetails of condition only but for the following case
221     * for eg Select * from Orders left Outer Join "Order Details" on Orders.OrderId = 11111
222     * where "Orders Details".OrderId is null
223     * we need not to change the type as simple Join .
224     * and if Condition TableDetails had been passed then we would not have any indication that
225     * the tableDetails were of null Predicate.
226     *
227     * @return
228     * @throws DException
229     */

230
231    public _TablePlan getExecutionPlan(_ServerSession session, booleanvalueexpression bve, _DatedFramework datedFrameWork, _QueryColumns queryColumns, _Order order0, ConditionArray conditionArray) throws DException {
232      queryColumns0=queryColumns;
233
234       initializeBvePlan(bve);
235       initializeOrderPlan(session, order0, queryColumns);
236       initializeConditionArray(conditionArray); // ConditionArray is used to know the tableDetails of Conditions
237
tablePlans = _fromclause3.getTablePlan(session, datedFrameWork, resultantBvePlan, orderPlan, queryColumns, conditionArray);
238       return createTableExpressionPlan(session);
239    }
240
241
242    /**
243     * It performs the following steps -
244     * 1. It merges the condition of 'from clause' in condition plan.
245     * 2. It initializes the mapping of table, single table plan and execution
246     * plan of that table.
247     * 3. It merges the join conditions among the table plans obtained from 'from
248     * clause'.
249     * 4. It makes a single plan for all the plans obtained from 'from clause'
250     * 5. Finally it makes plan for this tableexpression.
251     * @param session
252     * @return
253     * @throws DException
254     */

255
256    private TableExpressionPlan createTableExpressionPlan(_ServerSession session) throws DException {
257       mergeFromClauseConditioninResultantBvePlan();
258       initializeMapping();
259       mergeJoinCondition(session);
260       joinMissingLink();
261
262
263       return new TableExpressionPlan(finalTablePlan, resultantBvePlan, orderPlan,
264                                      _Optwhereclause2 == null ? null:GeneralPurposeStaticClass.getUnderLyingReferencesOnly(_Optwhereclause2.getReferences(tableDetails),tableDetails),
265                                      _Opthavingclause0 == null ? null:GeneralPurposeStaticClass.getUnderLyingReferencesOnly(_Opthavingclause0.getReferences(tableDetails),tableDetails)
266                                      );
267    }
268
269    /**
270     * It adds all the single table conditions and join conditions in passed
271     * condition array. It is required to check whether any present qualified
272     * join needs to be converted into simple joins.
273     * @param conditionArray
274     * @throws DException
275     */

276
277    private void initializeConditionArray(ConditionArray conditionArray) throws DException {
278       if (_Optwhereclause2 != null) {
279          if (conditionArray == null) {
280             conditionArray = new ConditionArray();
281          }
282          _BVEPlan bvePlan = _Optwhereclause2.getExecutionPlan();
283          _BVESingleTablePlan[] bveSingleTablePlans = bvePlan.getBVESingleTablePlans();
284          if (bveSingleTablePlans != null) {
285             for (int i = 0; i < bveSingleTablePlans.length; i++) {
286                conditionArray.addCondition(bveSingleTablePlans[i].getCondition());
287             }
288          }
289          _AllTablesJoinRelation allTablesJoinRelation = bvePlan.getAllTableJoinRelation();
290          if (allTablesJoinRelation != null) {
291             _JoinRelation[] joinRelations = allTablesJoinRelation.getRelations();
292             for (int i = 0; i < joinRelations.length; i++) {
293                conditionArray.addCondition(joinRelations[i].getCondition());
294             }
295          }
296       }
297    }
298
299    /**
300     * It merges the FromClause Conditions in resultantBvePlan. From Clause bve's
301     * comes in to existence
302     * a) When the inner join is Present
303     * b) Qualified Join is converted to simple Join.
304     * c) Optimizable View is present
305     * @throws DException
306     */

307
308    private void mergeFromClauseConditioninResultantBvePlan() throws DException {
309       _BVEPlan fromBvePlan = _fromclause3.getBveExecutionPlan();
310       resultantBvePlan = BVEPlanMerger.mergeTablePlansWithAnd(resultantBvePlan, fromBvePlan);
311    }
312
313    /**
314     * It is required to check whether passed single table order plans are
315     * same or not. It is required to check the redundancy of sorting needs of
316     * group by and order by.
317     * @param singleTableOrderPlan1
318     * @param singleTableOrderPlan2
319     * @return
320     * @throws DException
321     */

322
323    private boolean checkSequence(_SingleTableOrderPlan[] singleTableOrderPlan1, _SingleTableOrderPlan[] singleTableOrderPlan2) throws DException {
324       int count = (singleTableOrderPlan1.length < singleTableOrderPlan2.length) ? singleTableOrderPlan1.length : singleTableOrderPlan2.length;
325       for (int i = 0; i < count; i++) {
326          if (!compareOrdersAndColumns(singleTableOrderPlan1[i].getOrder(), singleTableOrderPlan2[i].getOrder())) {
327             return false;
328          }
329       }
330       return true;
331    }
332
333    /**
334     * It is required to check whether passed orders are same or not. It is
335     * required to check the redundancy of sorting needs of group by and order by.
336     * @param order1
337     * @param order2
338     * @return
339     * @throws DException
340     */

341
342    private boolean checkSequence(_Order order1, _Order order2) throws DException {
343       return (compareOrdersAndColumns(order1, order2));
344    }
345
346    /**
347     * It is used to check whether columns and orderspecification(asc/desc) of
348     * both orders are same or not.
349     * @param order1
350     * @param order2
351     * @return
352     * @throws DException
353     */

354
355    private boolean compareOrdersAndColumns(_Order order1, _Order order2) throws DException {
356       String JavaDoc[] str1 = order1.getColumns();
357       String JavaDoc[] str2 = order2.getColumns();
358       boolean[] result1 = order1.getOrderOfColumns();
359       boolean[] result2 = order2.getOrderOfColumns();
360       int length = (str1.length < str2.length) ? str1.length : str2.length;
361       for (int i = 0; i < length; i++) {
362          if (!str1[i].equalsIgnoreCase(str2[i]) || ! (result1[i] == result2[i])) {
363             return false;
364          }
365       }
366       return true;
367    }
368
369    /**
370     * initializeBvePlan method merges the BVEPlan of "where Clause" , "Having ",
371     * "Inner Join of On condition" and "View BvePlan"
372     * @param bve - bve of the View
373     * @return
374     * @throws DException
375     */

376
377    private void initializeBvePlan(booleanvalueexpression bve) throws DException {
378       resultantBvePlan = bve == null ? null : bve.getExecutionPlan();
379       resultantBvePlan = _Optwhereclause2 == null ? resultantBvePlan : BVEPlanMerger.mergeTablePlansWithAnd(resultantBvePlan, _Optwhereclause2.getExecutionPlan());
380       resultantBvePlan = _Opthavingclause0 == null ? resultantBvePlan : BVEPlanMerger.mergeTablePlansWithAnd(resultantBvePlan, _Opthavingclause0.getExecutionPlan());
381       resultantBvePlan = createLayerOfBveAllTablePlan(resultantBvePlan);
382    }
383
384    /**
385     * This method is used to add the layer of BVEAllTablePlan to passed BvePlan.
386     * It is done because we need the join condition of inner join present in
387     * fromClause. So this BveAllTablePlan is passed to fromClause so that it can
388     * add join conditions to this plan and it will be reflected in this class.
389     * we can also have BveSingleTablePlan which will be shifted to singletable,
390     * so in these case we need the cover of BveAllTablePlan.
391     *
392     * @param bvePlanPassed
393     * @return
394     * @throws DException
395     */

396
397    private _BVEPlan createLayerOfBveAllTablePlan(_BVEPlan bvePlanPassed) throws DException {
398       if (bvePlanPassed == null) {
399          return new BVEAllTablePlan(null, null, null);
400       } else if (bvePlanPassed.getType() == BVEConstants.BVESINGLETABLEPLAN) {
401          return new BVEAllTablePlan(new _BVESingleTablePlan[] { (_BVESingleTablePlan) bvePlanPassed}
402                                     , null, null);
403       } else if (bvePlanPassed.getType() == BVEConstants.BVEAGGREGATEPLAN) {
404          booleanvalueexpression aggregateCondition = bvePlanPassed.getAggregateCondition();
405          bvePlanPassed = new BVEAllTablePlan(null, null, null);
406          ( (BVEAllTablePlan) bvePlanPassed).andAggregateCondition(aggregateCondition);
407          return bvePlanPassed;
408       }
409       return bvePlanPassed;
410    }
411
412    /**
413     * InitializeMapping Creates an two2DArray whose length is the number of
414     * tables involved. The 2DArray Contains the tableName at 0th Position ,
415     * SingleTablePlan at 1st position , Execution Plan at 2nd Position.
416     * eg A LOJ B on Condition will have the following mapping
417     * A SingleTablePlan[A] QualifiedLeftPlan[AB]
418     * B SingleTablePlan[B] QualifiedLeftPlan[AB]
419     * This is used in merging of join condition. SingleTablePlans are used for
420     * obtaining the cost of join relation and execution plan are actually used
421     * on which join conditions are merged. After merging, resultant plan replaces
422     * the execution plan of both tables involved in condition.
423     * @throws DException
424     */

425
426    private void initializeMapping() throws DException {
427       int sizeOfMapping = 0;
428       int length = tablePlans.length;
429       Object JavaDoc[] singleTblPlans = new Object JavaDoc[length];
430       for (int i = 0; i < length; i++) {
431          _SingleTablePlan singleTablePlans[] = tablePlans[i].getSingleTablePlans();
432          sizeOfMapping += singleTablePlans.length;
433          singleTblPlans[i] = singleTablePlans;
434       }
435       tableAndQualifiedPlan = new Object JavaDoc[sizeOfMapping][3];
436       int index = 0;
437       for (int i = 0; i < length; i++) {
438
439          _SingleTablePlan singleTablePlans[] = (_SingleTablePlan[]) singleTblPlans[i];
440          for (int j = 0; j < singleTablePlans.length; j++) {
441             tableAndQualifiedPlan[index][0] = singleTablePlans[j].getTableDetails()[0];
442             tableAndQualifiedPlan[index][1] = singleTablePlans[j];
443             tableAndQualifiedPlan[index++][2] = tablePlans[i];
444          }
445       }
446    }
447
448    /**
449     * MergeJoinCondition sorts the JoinRelation on the Basis of their capability
450     * to reduce the rows. Then apporopriately merges the JoinCondition in the
451     * tablePlans.
452     * @throws DException
453     */

454
455    private void mergeJoinCondition(_ServerSession session) throws DException {
456       if (resultantBvePlan == null) {
457          return;
458       }
459       _AllTablesJoinRelation allTablesJoinRelation = resultantBvePlan.getAllTableJoinRelation();
460       if (allTablesJoinRelation != null) {
461          /** @todo Changed of sort method for tableDetails at zeroth index */
462          allTablesJoinRelation.sort(tableAndQualifiedPlan, session);
463          mergeJoinRelations(allTablesJoinRelation);
464       }
465    }
466
467    /**
468     * Searches the tableName in the tableAndQualifiedPlan mapping and returns
469     * the index of that.
470     * @param tableName TableName need to be searched.
471     * @return
472     * @throws DException
473     */

474
475    private int getTablePosition(TableDetails table) throws DException {
476       int length = tableAndQualifiedPlan.length;
477       for (int i = 0; i < length; i++) {
478          if (ifExists( ( (_TablePlan) tableAndQualifiedPlan[i][2]), table)) {
479             return i;
480          }
481       }
482       throw new DException("DSE3516", new Object JavaDoc[] {table.getNameOfTable()}); // INVALID OPERATION
483
}
484
485    /**
486     * It is used to check whether passed table exists in the passed plan.
487     * @param tablePlan
488     * @param tableDetail
489     * @return
490     * @throws DException
491     */

492
493    private boolean ifExists(_TablePlan tablePlan, TableDetails tableDetail) throws DException {
494       TableDetails[] tds = tablePlan.getTableDetails();
495       for (int i = 0; i < tds.length; i++) {
496          if (tds[i] == tableDetail) {
497             return true;
498          }
499       }
500       return false;
501    }
502
503    /**
504     * It updates the tableAndQualifiedPlan Mapping's ExecutionPlan at the
505     * position specified.
506     * @param mappingPositions
507     * @param tablePlan
508     * @throws DException
509     */

510
511    public void updateMapping(int[] mappingPositions, _TablePlan tablePlan) throws DException {
512       for (int i = 0; i < mappingPositions.length; i++) {
513          tableAndQualifiedPlan[mappingPositions[i]][2] = tablePlan;
514       }
515       TableDetails[] tableDetails = tablePlan.getViewTableDetails();
516       int[] tablePositions = getTablePositionFromMapping(tableDetails);
517       for (int i = 0; i < tablePositions.length; i++) {
518          tableAndQualifiedPlan[tablePositions[i]][2] = tablePlan;
519       }
520    }
521
522    /**
523     * Searches the tables in the tableAndQualifiedPlan mapping and returns
524     * the index of that.
525     * @param tableName TableName need to be searched.
526     * @return
527     * @throws DException
528     */

529    /** @todo Changed its arg as TableDetails instead of tableNames */
530
531    private int[] getTablePositionFromMapping(TableDetails[] tableDetails) throws DException {
532       int intArray[] = new int[tableAndQualifiedPlan.length];
533       int index = 0;
534       for (int j = 0; j < tableDetails.length; j++) {
535          for (int i = 0; i < tableAndQualifiedPlan.length; i++) {
536             if (tableAndQualifiedPlan[i][0] == tableDetails[j]) {
537                intArray[index++] = i;
538                break;
539             }
540          }
541       }
542       int[] returnArray = new int[index];
543       System.arraycopy(intArray, 0, returnArray, 0, index);
544       return returnArray;
545    }
546
547    /**
548     * This method is used to merge all the join relations represented by
549     * AllTablesJoinRelation among the plans obtained from 'from clause'.
550     * The steps involved are -
551     * 1. Execution plan of both the tables, involved in join condition, are
552     * retrieved from mapping.
553     * 2. Then a plan is formed after merging join condition for these two plans.
554     * 3. Correspondingly update the mapping with this plan. Now both the tables
555     * will contain this plan as execution plan in mapping.
556     * @param allTablesJoinRelation
557     * @throws DException
558     */

559
560    private void mergeJoinRelations(_AllTablesJoinRelation allTablesJoinRelation) throws DException {
561       _JoinRelation joinRelations[] = allTablesJoinRelation.getRelations();
562       int length = joinRelations.length;
563       for (int i = 0; i < length; i++) {
564          TableDetails[] tableDetails = GeneralPurposeStaticClass.getAllTableDetails(joinRelations[i].getCondition());
565          int mappingPosition1 = getTablePosition(tableDetails[0]);
566          _TablePlan tablePlan1 = (_TablePlan) tableAndQualifiedPlan[mappingPosition1][2];
567          int mappingPosition2 = getTablePosition(tableDetails[1]);
568          _TablePlan tablePlan2 = (_TablePlan) tableAndQualifiedPlan[mappingPosition2][2];
569          int[] tablePositions = new int[] {mappingPosition1, mappingPosition2};
570          tablePlans = mergingOfJoinRelation(tablePlan1, tablePlan2, joinRelations[i], tableDetails, tablePositions, tablePlans);
571       }
572    }
573
574    /**
575     * It is required when we have to merge join condition in OrderSequenceplan and
576     * the tables involved in join condition are not present at consecutive
577     * location in OrderSequencePlan. In this case TemporaryMerge plan is made
578     * and placed in OrderSequencePlan.
579     * @param orderSequencePlan OrderSequencePlan which needs to be changed
580     * @param bve condition which is to be merged
581     * @param index1 Starting index of tablePlan List from which we want to create the TemporaryMerge
582     * @param index2 Ending index of tablePlan List from which we want to create the TemporaryMerge
583     * @throws DException
584     */

585
586    private void prepareTableMergeAndUpdateTablePlans(_TablePlan orderSequencePlan, booleanvalueexpression bve, int index1, int index2) throws DException {
587       _TablePlan[] tp = ( (OrderSequencePlan) orderSequencePlan).getTablePlans();
588       int len = tp.length;
589       TemporaryMerge tempMerge = new TemporaryMerge();
590       for (int i = index1; i <= index2; i++) {
591          tempMerge.addTablePlan(tp[i]);
592       }
593       tempMerge.addCondition(bve);
594       _TablePlan[] newTp = new _TablePlan[tp.length - (index2 - index1)];
595       System.arraycopy(tp, 0, newTp, 0, index1);
596       newTp[index1] = tempMerge;
597       System.arraycopy(tp, index2 + 1, newTp, index1 + 1, tp.length - index2 - 1);
598       ( (OrderSequencePlan) orderSequencePlan).setPlans(newTp);
599    }
600
601    /**
602     * It is required when we have to merge join condition in OrderSequenceplan and
603     * the tables involved in join condition are present at consecutive
604     * location in OrderSequencePlan. In this case TwoTableJoin plan is made
605     * and placed in OrderSequencePlan.
606     * @param orderSequencePlan OrderSequencePlan whose tablePlan List will be changed
607     * @param bve condition which is to merged
608     * @param index1 Plan's index of the new twoTableJOinPlan
609     * @param index2 Plan's index of the new twoTableJOinPlan
610     * @throws DException
611     */

612
613    private void prepareTwoTableJoinPlanAndUpdateTablePlans(_TablePlan orderSequencePlan, booleanvalueexpression bve, int index1, int index2) throws DException {
614       _TablePlan[] tp = ( (OrderSequencePlan) orderSequencePlan).getTablePlans();
615       int len = tp.length;
616       TwoTableJoinPlan ttJp = new TwoTableJoinPlan(tp[index1], tp[index2], bve);
617       _TablePlan[] newTp = new _TablePlan[tp.length - 1];
618       System.arraycopy(tp, 0, newTp, 0, index1);
619       newTp[index1] = ttJp;
620       System.arraycopy(tp, index1 + 1, newTp, index1 + 1, index2 - index1 - 1);
621       System.arraycopy(tp, index2 + 1, newTp, index2, newTp.length - index2);
622       ( (OrderSequencePlan) orderSequencePlan).setPlans(newTp);
623    }
624
625    /**
626     * Makes the final ExecutablePlan. It removes the cover of OrderSequencePlan
627     * and TemporaryMerge, if they are present in plan. Because both these plans
628     * are not executable.
629     * Eg for Query like Select * from A, B , C where A.id = B.id
630     * TablePlans have TTJp[AB] , STP[C]
631     * but we need a single Execution Plan so we make a NestedLoopJoinPlan which
632     * will do the Cartesian of the underLyingPlans
633     * @throws DException
634     */

635
636    private void joinMissingLink() throws DException {
637       int length = tablePlans.length;
638
639       for (int i = 0; i < length; i++) {
640          tablePlans[i] = tablePlans[i].joinMissingLink();
641       }
642
643       if (tablePlans.length > 1) {
644          finalTablePlan = new NestedLoopJoinPlan(tablePlans);
645       } else {
646          finalTablePlan = tablePlans[0];
647       }
648    }
649
650    /**
651     * Returns the columns involved in from clause.
652     * @return array of columns
653     * @throws DException
654     */

655
656    public ColumnDetails[] getFromClauseColumnDetails() throws DException {
657       return _fromclause3.getColumnDetails();
658    }
659
660    /**
661     * Returns the columns involved in where clause.
662     * @return array of columns
663     * @throws DException
664     */

665
666    public ColumnDetails[] getWhereClauseColumnDetails() throws DException {
667       return _Optwhereclause2 != null ? _Optwhereclause2.getColumnDetails()
668           : null;
669    }
670
671    /**
672     * Returns the columns involved in group by clause.
673     * @return array of columns
674     * @throws DException
675     */

676
677    public ColumnDetails[] getGroupByColumnDetails() throws DException {
678       return _Optgroupbyclause1 != null ? _Optgroupbyclause1.getColumnDetails()
679           : null;
680    }
681
682    /**
683     * Returns the columns involved in having clause.
684     * @return array of columns
685     * @throws DException
686     */

687
688    public ColumnDetails[] getHavingClauseColumnDetails() throws DException {
689       return _Opthavingclause0 != null ? _Opthavingclause0.getColumnDetails()
690           : null;
691    }
692
693    /**
694     * Returns the string representation of from clause
695     * @return
696     */

697
698    public String JavaDoc getfromClause() {
699       return _fromclause3.toString();
700    }
701
702    /**
703     * Returns the string representation of group by clause
704     * @return
705     */

706
707    public String JavaDoc getGroupByClause() {
708       return _Optgroupbyclause1 == null ? null : _Optgroupbyclause1.toString();
709    }
710
711    /**
712     * Returns the string representation of having clause
713     * @return
714     */

715
716    public String JavaDoc getHavingClause() {
717       return _Opthavingclause0 == null ? null : _Opthavingclause0.toString();
718    }
719
720    /**
721     * Returns the string representation of where clause
722     * @return
723     */

724
725    public String JavaDoc getWhereClause() {
726       return _Optwhereclause2 == null ? null : _Optwhereclause2.toString();
727    }
728
729    /**
730     * Returns all the tables involved in from clause. If view is present then
731     * this view is returned as table.
732     * @return
733     * @throws DException
734     */

735
736    public TableDetails[] getViewTableDetails() throws DException {
737       return _fromclause3.getViewTableDetails();
738    }
739
740    /**
741     * This method is used to get all those columns of 'from clause' which avoids
742     * scope management rule of semantic checking.
743     * @return
744     * @throws DException
745     */

746
747    public _Reference[] getUnderlyingReferences() throws DException {
748       return _fromclause3.getUnderlyingReferences();
749    }
750
751    /**
752     * Returns the condition which will be solved on the result of group by and
753     * aggregate functions.
754     * @return
755     * @throws DException
756     */

757
758    public booleanvalueexpression getAggregateCondition() throws DException {
759       return resultantBvePlan == null ? null
760           : resultantBvePlan.getAggregateCondition();
761    }
762
763    /**
764     * This method firstly check whether the sorting needs of group by and passed
765     * order is similar or not. If similar then sorting is performed only once.
766     * otherwise, the order plans of group by and passed order are merged to
767     * find the sorting needs of select query.
768     * e.g.
769     * select a ,b from A group by a,b order by b
770     * if b is not a primary key then the order and group by plan will not be
771     * mergerd. This method checks for such cases by calling the checkForGroupAndOrderRedundant.
772     * @param session
773     * @param orderPlan0 OrderPlan of the ViewPlan
774     * @throws DException
775     */

776
777    private void initializeOrderPlan(_ServerSession session, _Order viewOrder, _QueryColumns queryCols) throws DException {
778       orderPlan = checkForGroupAndOrderRedundant(viewOrder, session, queryCols);
779       if (orderPlan != null) {
780          return;
781       }
782       if (viewOrder != null) {
783          orderPlan = viewOrder.getOrderPlan(session);
784       }
785       if (_Optgroupbyclause1 != null) {
786          _Order groupOrder = _Optgroupbyclause1.getOrder(queryCols); // It returns the cloned cloumns.
787
orderPlan = getMergedGroupAndOrderPlan(orderPlan, groupOrder.getOrderPlan(session));
788       }
789    }
790
791    /**
792     * This method is used to obtain the resultant sorting needs of select query
793     * by merging order plan of group by and passed order. The following cases
794     * can arise -
795     * GroupByPlan-SingleTableOrder , Order-SingleTableOrder
796     * 1) Check whether column are same and in same order. If same we make
797     * only one singleTableOrder.
798     * a. Select * from A, B group by A.id order by A.id , B.id
799     * i. Only one SingleTableOrder is Created ie SingleTableOrderPlan(A.id , B.id)
800     *
801     * b. Select * from A, B group by B.id order by A.id , B.id
802     * i. SingleTableOrderPlan(B.id)
803     * ii. JoinLevelOrderPlan(A.id , B.id)
804     *
805     * GroupByPlan-SingleTableOrder , Order-JoinLevelOrderPlan
806     * An OrderPlan which contains SingleTableOrder of Group and Order of JoinLevelOrderPlan
807     * GroupByPlan-SingleTableOrder , Order-GroupByPlan
808     * An OrderPlan which contains SingleTableOrder of Group and Order of GroupByOrderPlan.
809     *
810     * GroupByPlan-JoinLevelOrder , Order-SingleTableOrder
811     * An OrderPlan which contains JoinLevelOrder of Group and SingleTableOrder of GroupBy in GroupByLevel Order
812     *
813     * GroupByPlan-JoinLevelOrder , Order-JoinLevelOrder
814     * If Both are same then an OrderPlan which contains the common JoinLevelOrderPlan
815     * If different then an OrderPlan
816     * Whose joinOrderPlan contains GroupByPlan-JoinLevelOrder
817     * And GroupByLevelOrder contains, Order-JoinLevelOrder
818     * GroupByPlan-JoinLevelOrder , Order-GroupByLevelOrder
819     * An OrderPlan which contains JoinLevelOrder of GroupBy and GroupByLevelOrder of OrderBy.
820     *
821     * @param orderByOrderPlan
822     * @param groupByOrderPlan
823     * @return
824     * @throws DException
825     */

826
827    private _OrderPlan getMergedGroupAndOrderPlan(_OrderPlan orderByOrderPlan, _OrderPlan groupByOrderPlan) throws DException {
828       if (orderByOrderPlan == null) {
829          return groupByOrderPlan;
830       }
831       _SingleTableOrderPlan[] stopOrderBy = orderByOrderPlan.getSingleTableOrderPlans();
832       _SingleTableOrderPlan[] stopGroupBy = groupByOrderPlan.getSingleTableOrderPlans();
833       if (stopGroupBy != null) {
834          if (stopOrderBy != null) { // Both contains SingleTableOrderPlan
835
return mergeSingleTableOrderPlans(stopOrderBy, stopGroupBy, orderByOrderPlan, groupByOrderPlan);
836          }
837          _Order joinOrderPlanOrderBy = orderByOrderPlan.getJoinLevelOrder();
838          /*
839               Select O.OrderID,SUM(O.OrderID+OD.OrderID) From Orders O, "Order Details" OD
840               Where O.OrderID = OD.OrderID
841               Group By O.OrderID
842               Order By SUM(O.OrderID+OD.OrderID)
843           */

844          if (joinOrderPlanOrderBy != null) { // order by has joinOrderPlan and group by has singleTableOrderPlan
845
groupByOrderPlan.setJoinOrderPlan(joinOrderPlanOrderBy);
846             return groupByOrderPlan;
847          }
848          groupByOrderPlan.setGroupByOrderPlan(orderByOrderPlan.getGroupByLevelOrder()); // order by has groupOrderPlan and group by has singleTableOrderPlan
849
return groupByOrderPlan;
850       }
851       if (stopOrderBy != null) { // Order By contains singleTableOrderPlan , groupBy
852
groupByOrderPlan.setGroupByOrderPlan(OrderPlanMerger.getOrder(stopOrderBy));
853          return groupByOrderPlan;
854       }
855       _Order joinOrderPlanOrderBy = orderByOrderPlan.getJoinLevelOrder();
856       _Order joinOrderPlanGroupBy = groupByOrderPlan.getJoinLevelOrder();
857       if (joinOrderPlanOrderBy != null) { // Both Contains JoinOrderPlan
858
return mergeJoinOrderPlan(joinOrderPlanOrderBy, joinOrderPlanGroupBy, orderByOrderPlan, groupByOrderPlan);
859       }
860
861       groupByOrderPlan.setGroupByOrderPlan(orderByOrderPlan.getGroupByLevelOrder()); // order by has groupOrderPlan and group by has joinOrderPlan
862
return groupByOrderPlan;
863    }
864
865    /**
866     * This method is used to merge both the arrays of Single Table Order Plans.
867     * If they are same, then order plan of largest length is used. Otherwise,
868     * single table orders of OrderByPlan will be applied at groupby level.
869     * For Query like
870     * a) Select CustomerID,EmployeeID from Orders
871     * Group By CustomerID,EmployeeID
872     * Order By EmployeeID
873     * We will generate
874     * OrderPlan having
875     * STOP > EmployeeID,CustomerID
876     *
877     * b) Select CustomerID,EmployeeID from Orders
878     * Group By EmployeeID , CustomerID
879     * Order By EmployeeID
880     * OrderPlan having
881     * STOP > EmployeeID , CustomerId
882     * @param stop1
883     * @param stop2
884     * @param orderByOrderPlan
885     * @param groupByOrderPlan
886     * @return
887     * @throws DException
888     */

889    private _OrderPlan mergeSingleTableOrderPlans(_SingleTableOrderPlan[] stop1, _SingleTableOrderPlan[] stop2, _OrderPlan orderByOrderPlan, _OrderPlan groupByOrderPlan) throws DException {
890       if (!checkSequence(stop1, stop2)) {
891          groupByOrderPlan.setGroupByOrderPlan(OrderPlanMerger.getOrder(stop1));
892          return groupByOrderPlan;
893       }
894       return (stop1.length >= stop2.length) ? orderByOrderPlan : groupByOrderPlan;
895    }
896
897    /**
898     * It is required to check the redundancy of sorting needs of groupby and
899     * orderby in case when join level order is present in both. If join level
900     * order plan of groupby is same as that of orderby, then query is sorted
901     * only once instead of twice.
902     * @param joinOrderPlanOrderBy
903     * @param joinOrderPlanGroupBy
904     * @param orderByOrderPlan
905     * @param groupByOrderPlan
906     * @return
907     * @throws DException
908     */

909    private _OrderPlan mergeJoinOrderPlan(_Order joinOrderPlanOrderBy, _Order joinOrderPlanGroupBy, _OrderPlan orderByOrderPlan, _OrderPlan groupByOrderPlan) throws DException {
910       if (!checkSequence(joinOrderPlanOrderBy, joinOrderPlanGroupBy)) {
911          groupByOrderPlan.setGroupByOrderPlan(joinOrderPlanOrderBy);
912          return groupByOrderPlan;
913       }
914       return (joinOrderPlanOrderBy.getColumnIndexes().length >= joinOrderPlanGroupBy.getColumnIndexes().length) ? orderByOrderPlan : groupByOrderPlan;
915    }
916
917    public String JavaDoc toString() {
918       StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
919       sb.append(" ");
920       sb.append(_fromclause3);
921       sb.append(" ");
922       if (_Optwhereclause2 != null) {
923          sb.append(_Optwhereclause2);
924       }
925       sb.append(" ");
926       if (_Optgroupbyclause1 != null) {
927          sb.append(_Optgroupbyclause1);
928       }
929       sb.append(" ");
930       if (_Opthavingclause0 != null) {
931          sb.append(_Opthavingclause0);
932       }
933       return sb.toString();
934    }
935
936    public Object JavaDoc clone() throws CloneNotSupportedException JavaDoc {
937       tableexpression tempClass = new tableexpression();
938       if (_Opthavingclause0 != null) {
939          tempClass._Opthavingclause0 = (havingclause) _Opthavingclause0.clone();
940       }
941       if (_Optgroupbyclause1 != null) {
942          tempClass._Optgroupbyclause1 = (groupbyclause) _Optgroupbyclause1.clone();
943       }
944       if (_Optwhereclause2 != null) {
945          tempClass._Optwhereclause2 = (whereclause) _Optwhereclause2.clone();
946       }
947       tempClass._fromclause3 = (fromclause) _fromclause3.clone();
948       return tempClass;
949    }
950
951    /**
952     * This method merges the JoinCondition in an OrderSequencePlan ,
953     * orderSequencePlan contains both the Plan of JoinRelation.
954     * eg Select * from Orders , "Order Details" where Orders.OrderId = "Order Details".OrderId
955     * order by Orders.OrderId , "Order Details".OrderId
956     * then OrderSequencePlan will have two SingleTablePlans
957     * STOP[Orders] and STOP["Order Details"]
958     * Select * from Orders , Employees , "Order Details" where
959     * Orders.OrderId = "Order Details".OrderId order by Orders.OrderId ,
960     * Employees.employeeid, "Order Details".OrderId
961     * then OrderSequencePlan will have three SingleTablePlans
962     * STP[Orders] , STP[Employees] , STP["Order Details"]
963     * we will prepare TemporaryMerge which will have three SingleTablePlan
964     * STP[Orders] , STP[Employees] , STP["Order Details"]
965     * with remainingCondition Orders.OrderId = "Order Details".OrderId
966     * @param tablePlan1
967     * @param joinRelation
968     * @throws DException
969     */

970    protected void mergeJoinRelationInOrderSequencePlan(_TablePlan tablePlan1, _JoinRelation joinRelation) throws DException {
971       TableDetails[] tableDetails = joinRelation.getTableDetails();
972       int index1 = ( (OrderTablePlanAbstract) tablePlan1).getIndex(tableDetails[0]);
973       int index2 = ( (OrderTablePlanAbstract) tablePlan1).getIndex(tableDetails[1]);
974       if (index1 > index2) {
975          int temp = index1;
976          index1 = index2;
977          index2 = temp;
978       }
979       if (index2 - index1 == 0) {
980          ( (OrderTablePlanAbstract) tablePlan1).setJoinConditionOfChild(index1, joinRelation);
981       } else {
982          if ( (index2 - index1) > 1) { //prepare TemporaryMerge
983
prepareTableMergeAndUpdateTablePlans(tablePlan1, joinRelation.getCondition(), index1, index2);
984          } else { //when TempMerge is not required.So Only TowTableJoinPlan 'll be formed.
985
prepareTwoTableJoinPlanAndUpdateTablePlans(tablePlan1, joinRelation.getCondition(), index1, index2);
986          }
987       }
988    }
989
990    /**
991     * Merges the fromClause's condition plan with condition plan of where and
992     * having clause.
993     * @return
994     * @throws DException
995     */

996
997    public _BVEPlan getBveExecutionPlan() throws DException {
998       _BVEPlan fromBvePlan = _fromclause3.getBveExecutionPlan();
999       return BVEPlanMerger.mergeTablePlansWithAnd(resultantBvePlan, fromBvePlan);
1000   }
1001
1002   /**
1003    * A query is called simple when it contains only one table and which is not
1004    * a view. It should not contain groupby, where, having clause. For purpose,
1005    * refer to documentation of queryexpressionbody
1006    *
1007    * Method isSimpleQuery also written in fromClause so as to avoid calling getTableDetails.
1008    * The previous approach(getTableDetails) leads to NPE in case of natural join.
1009    *
1010    * @return
1011    * @throws DException
1012    */

1013   public boolean isSimpleQuery(_ServerSession serverSession) throws DException {
1014      if (serverSession != null) {
1015        /** @todo Modification in _optwhereclause condition due to requirement of updatable resultset using where clause in Compiere/CRM software ..--Manoj Kr. Nov. 2,2004 */
1016       return _Optgroupbyclause1 == null && (_Optwhereclause2 == null || (_Optwhereclause2 != null && !_Optwhereclause2.checkForSubquery() &&!_Optwhereclause2.hasContainClause() ))
1017               && _Opthavingclause0 == null && _fromclause3.isSimpleQuery(serverSession);
1018
1019     }
1020      return _Optgroupbyclause1 == null && _Optwhereclause2 == null
1021         && _Opthavingclause0 == null
1022         && tableDetails.length == 1 && tableDetails[0].getTableType() == TypeConstants.VIEW;
1023   }
1024
1025   /**
1026    * Documentation for purpose or requirement, refer the documenation of
1027    * queryexpressionbody.
1028
1029    * Detailed documentation is given below.
1030    *
1031    * It is needed when the View is Optimizable.It gives the Array Of Plans involved
1032    * in the view
1033    * eg Select * from View1 v where V.Id =1 order by V.Id1
1034    * View1 "Select OrderId as Id, EmployeeID as Id1 from Orders inner join "Order Details" where Orders.OrderId = "Order Details".OrderId";
1035    * and this tableexpession is of Query "Select OrderId as Id from Orders inner join "Order Details" where
1036    * Orders.OrderId = "Order Details".OrderId"
1037    * ie View1
1038    * then
1039    * @param session
1040    * @param condition will have V.Id = 1 with it's tableDetails changed
1041    * @param viewOrder will have V.id1 with it's tableDetails changed
1042    * @param queryCols V.id , V.id1 with there tableDetails changed
1043    * @param conditionArray - V.Id =1 condition
1044    * @return
1045    * @throws DException
1046    *--------------------------
1047    *REQUIREMENT OF ARGUMENTS |
1048    *--------------------------
1049    *Condition >> This are SingleLevel Conditions of View .
1050    * For the above view we would like to shift the condition V.Id = 1 to the Orders Table as V.Id column is
1051    * actually of Orders.OrderId .Since in this tableExpression/querySpecification we are having the tablePlan
1052    * of Orders so we need to pass the information upto this level.
1053    *ViewOrder >> This are SingleLevel Conditions of View .
1054    * For the above view we would like to shift the order on column V.Id to the Orders Table as V.Id column is
1055    * actually of Orders.OrderId .Since in this tableExpression/querySpecification we are having the tablePlan
1056    * of Orders so we need to pass the information to this level.
1057    *QueryColumns >> QueryColumns helps to calculate the cost of Plan Generated.As it tells the columns involved in the
1058    * Query.There is always a cost of extracting any column from the Database.This cost calculation work
1059    * is done at SingleTablePlan.
1060    *ConditionArray >> For Changing the type of joins beacuse of the condition present in where clause or on clause
1061    * we need to pass the these conditions as they can change their meaning
1062    * for eg Select * from Orders left Outer Join "Order Details" on Orders.OrderId = 11111 where "Orders Details".OrderId > 1
1063    * This Query will act as Select * from Orders , "Order Details" where "Orders Details".OrderId > 1 and Orders.OrderId = 11111
1064    * We need to pass "Orders Details".OrderId > 1 information to qualifiedJoin of Orders left Outer Join "Order Details"
1065    * so that it can change treat as simple Join.
1066    * We could have passed TableDetails of condition only but for the following case
1067    * for eg Select * from Orders left Outer Join "Order Details" on Orders.OrderId = 11111
1068    * where "Orders Details".OrderId is null
1069    * we need not to change the type as simple Join .
1070    * and if Condition TableDetails had been passed then we would not have any indication that
1071    * the tableDetails were of null Predicate.
1072    *
1073    */

1074
1075   public _TablePlan[] getTablePlans(_ServerSession session, booleanvalueexpression condition, _Order viewOrder, _QueryColumns queryCols, ConditionArray conditionArray) throws DException {
1076      resultantBvePlan = mergeBvePlan(condition);
1077      resultantBvePlan = createLayerOfBveAllTablePlan(resultantBvePlan);
1078      initializeOrderPlan(session, viewOrder, queryCols);
1079      initializeConditionArray(conditionArray); // ConditionArray is used to know the tableDetails of Conditions
1080
tablePlans = _fromclause3.getTablePlan(session, null, resultantBvePlan, orderPlan, queryCols, conditionArray);
1081      return orderPlan != null && orderPlan.getJoinLevelOrder() != null ? new _TablePlan[] {createTableExpressionPlan(session)}
1082           : tablePlans;
1083   }
1084
1085   /**
1086    * Returns the order which will be applied on the result of group by.
1087    * @return
1088    * @throws DException
1089    */

1090
1091   public _Order getGroupByLevelOrder() throws DException {
1092      return orderPlan == null ? null : orderPlan.getGroupByLevelOrder();
1093   }
1094
1095   /**
1096    * It is used to check whether this query is eligible for 'For update' option.
1097    * Only those select Query, in which only single table is present and that table
1098    * should not be a view, is allowed. No group by or having should be present
1099    * for 'For update' option.
1100    * @throws DException
1101    */

1102
1103   public void checkSemanticForUpdate() throws DException {
1104      if (_Optgroupbyclause1 != null || (_Optwhereclause2 != null && _Optwhereclause2.checkForSubquery()) || tableDetails.length != 1 || tableDetails[0].getTableType() == TypeConstants.VIEW) {
1105         throw new DException("DSE6003", null);
1106      }
1107   }
1108
1109   /**
1110    * This method checks if either of order and Group by is redundant
1111    * e.g.
1112    * select a,b from A group by a,b order by b
1113    * if we rewrite the query as
1114    * select a,b from A group by b,a
1115    * the result is the same
1116    * as the above query thus the order by is redundant
1117    * Algo::
1118    * First the order column Details are got
1119    * Then the group by column details are got
1120    *
1121    * For each order column that is of reference type and order specification is not DESC
1122    * we check if the column exists in the group by columns
1123    * The view columns are checked
1124    * @param viewOrder
1125    * @param session
1126    * @param queryCols
1127    * @return
1128    * @throws DException
1129    */

1130   private _OrderPlan checkForGroupAndOrderRedundant(_Order viewOrder, _ServerSession session, _QueryColumns queryCols) throws DException {
1131      if (viewOrder == null || _Optgroupbyclause1 == null) {
1132         return null;
1133      }
1134      ColumnDetails[] orderCD = viewOrder.getColumnDetails();
1135      boolean[] orderSpecification = viewOrder.getOrderOfColumns();
1136      ColumnDetails[] groupCD = _Optgroupbyclause1.getOrder(queryCols).getColumnDetails();
1137      ArrayList result = new ArrayList();
1138      int i = 0;
1139      for (; i < orderCD.length; i++) {
1140         if (orderCD[i].getType() != REFERENCE || !orderSpecification[i]) {
1141            return null;
1142         }
1143         String JavaDoc column = orderCD[i].getAppropriateColumn();
1144         int j = 0;
1145         for (; j < groupCD.length; j++) {
1146            if(orderCD[i].getTable() == groupCD[j].getTable() && column.equalsIgnoreCase(groupCD[j].getAppropriateColumn())){
1147               result.add(groupCD[j]);
1148               break;
1149            }
1150         }
1151         if (j == groupCD.length) {
1152            return null;
1153         }
1154
1155      }
1156      if (i == orderCD.length) {
1157         for (int k = 0; k < groupCD.length; k++) {
1158            if (!result.contains(groupCD[k])) {
1159               result.add(groupCD[k]);
1160            }
1161         }
1162         return new SelectOrder( (ColumnDetails[]) result.toArray(new ColumnDetails[result.size()])).getOrderPlan(session);
1163      }
1164      return null;
1165   }
1166
1167   /**
1168    * For the documentation of underlying methods, refer the documentation of
1169    * queryexpressionbody.
1170    */

1171
1172   public _Reference[] getReferences(TableDetails[] tableDetails) throws DException {
1173      _Reference[] reference = null;
1174      if (_Optwhereclause2 != null) {
1175         reference = GeneralPurposeStaticClass.getJointReferences(reference, _Optwhereclause2.getReferences(tableDetails));
1176      }
1177      if (_Opthavingclause0 != null) {
1178         reference = GeneralPurposeStaticClass.getJointReferences(reference, _Opthavingclause0.getReferences(tableDetails));
1179      }
1180
1181      reference = GeneralPurposeStaticClass.getJointReferences(reference, _fromclause3.getUnderlyingReferences());
1182
1183      if (_Optgroupbyclause1 != null) {
1184        reference = GeneralPurposeStaticClass.getJointReferences(reference,_Optgroupbyclause1.getReferences(tableDetails));
1185      }
1186
1187      return reference;
1188   }
1189
1190   public Object JavaDoc[] getParameters(Object JavaDoc object) throws DException {
1191      Object JavaDoc[] param = _fromclause3.getParameters(object);
1192      if (_Optwhereclause2 != null) {
1193         param = addParameters(param, _Optwhereclause2.getParameters(object));
1194      }
1195      if (_Opthavingclause0 != null) {
1196         param = addParameters(param, _Opthavingclause0.getParameters(object));
1197      }
1198      return param;
1199   }
1200
1201   public TableDetails[] getTableDetails(_ServerSession session, ColumnDetails[] queryColumns) throws DException {
1202      if (tableDetails == null) {
1203         tableDetails = _fromclause3.getTableDetails(session, queryColumns);
1204      }
1205      return tableDetails;
1206   }
1207
1208   /**
1209    * This method adds all the columndetails present in query. This method
1210    * is different from getColumnDetails as getColumnDetails returns the
1211    * columns belong to this query while this method returns all the
1212    * columnDetails of this query as well as underlying query(either in
1213    * view or in subQuery present in condition)
1214    * This method is needed by DDL.
1215    * @param aList
1216    * @throws DException
1217    */

1218
1219   public void getColumnsIncluded(ArrayList aList) throws DException {
1220      _fromclause3.getColumnsIncluded(aList);
1221      if (_Optwhereclause2 != null) {
1222         _Optwhereclause2.getColumnsIncluded(aList);
1223      }
1224      if (_Optgroupbyclause1 != null) {
1225         _Optgroupbyclause1.getColumnsIncluded(aList);
1226      }
1227      if (_Opthavingclause0 != null) {
1228         _Opthavingclause0.getColumnsIncluded(aList);
1229      }
1230   }
1231
1232   /**
1233    * This method adds all the TableDetails present in query. This method
1234    * is different from getTableDetails as getTableDetails returns the
1235    * tables belong to this query while this method returns all the
1236    * TableDetails of this query as well as underlying query(either in
1237    * view or in subQuery present in condition)
1238    * This method is needed by DDL.
1239    * @param aList
1240    * @throws DException
1241    */

1242
1243   public void getTablesIncluded(ArrayList aList) throws DException {
1244      _fromclause3.getTablesIncluded(aList);
1245      if (_Optwhereclause2 != null) {
1246         _Optwhereclause2.getTablesIncluded(aList);
1247      }
1248      if (_Optgroupbyclause1 != null) {
1249         _Optgroupbyclause1.getTablesIncluded(aList);
1250      }
1251      if (_Opthavingclause0 != null) {
1252         _Opthavingclause0.getTablesIncluded(aList);
1253      }
1254   }
1255
1256   public ParameterInfo[] getParameterInfo() throws DException {
1257      ParameterInfo[] p1 = _fromclause3.getParameterInfo();
1258      ParameterInfo[] p2 = null, p3 = null;
1259      if (_Optwhereclause2 != null) {
1260         p2 = _Optwhereclause2.getParameterInfo();
1261      }
1262      if (_Opthavingclause0 != null) {
1263         p3 = _Opthavingclause0.getParameterInfo();
1264      }
1265      ArrayList aList = new ArrayList(5);
1266      if (p1 != null) {
1267         aList.addAll(Arrays.asList(p1));
1268      }
1269      if (p2 != null) {
1270         aList.addAll(Arrays.asList(p2));
1271      }
1272      if (p3 != null) {
1273         aList.addAll(Arrays.asList(p3));
1274      }
1275      return (ParameterInfo[]) aList.toArray(new ParameterInfo[0]);
1276   }
1277
1278   /**
1279    * This method is used to verify the values given by the user.
1280    * <ol><li>Checks the conditional Column values given by user.
1281    * If the values mismatchs the join condition, exception is thrown.</li>
1282    * <li>Checks the values must satisfy where clause condition, if violates,
1283    * exception is thrown</li></ol>
1284    **/

1285
1286   public void verifyValues(_VariableValueOperations variableValueOperation) throws DException {
1287     return ;
1288     /** @todo Following code is commented due to compiere/CRM software requirement of updatable resultset. -- Manoj Kr. Nov. 2,2004
1289      * */

1290   }
1291
1292   /**
1293    * This method is used to set the default values according to where clause and join condition,
1294    * <li><li>If user gives value of one of the join specification conditional column used in join
1295    * condition, value is set for the unspecified conditonal column to maintain the join condition.</li>
1296    * <li>If the where clause conditional column value is not given by the user, it is set
1297    * as default value.</li></ol>
1298    */

1299
1300   public void setDefaultValues(_VariableValueOperations variableValueOperation) throws DException {
1301      ( (VariableValueOperations) variableValueOperation).setFlag(false);
1302      _fromclause3.setDefaultValues(variableValueOperation);
1303      if (_Opthavingclause0 != null) {
1304         _Opthavingclause0.setDefaultValues(variableValueOperation);
1305      }
1306   }
1307
1308   public _Reference[] checkSemantic(_ServerSession session, ColumnDetails[] queryColumns, boolean checkUserRight) throws DException {
1309      _Reference[] references = _fromclause3.checkSemantic(session, queryColumns, checkUserRight); // checking for OnCondition Columns used in Qualified Join
1310
if (_Optwhereclause2 != null) {
1311         references = GeneralPurposeStaticClass.getJointReferences(references, _Optwhereclause2.checkSemantic(session));
1312      }
1313      if (_Opthavingclause0 != null) {
1314         _Reference[] temp = _Opthavingclause0.checkSemantic(session);
1315         references = GeneralPurposeStaticClass.getJointReferences(references, temp);
1316      }
1317      return references;
1318   }
1319
1320   /**
1321    * In this method columnMappingHandler is passed as parameter which maintains
1322    * a list of the tables in which insertion will be made for a insert operation
1323    * in select query with qualified join chain. This method adds the tables if there
1324    * exists one or more tables for insert operation according to the values specified by the user.
1325    */

1326
1327   public void setTablesForInsertion(ColumnMappingHandler columnMapping, _VariableValueOperations vv) throws DException {
1328     return;
1329     /** @todo Following code is commented due to compiere/CRM software requirement of updatable resultset. --Manoj Kr. Nov. 2,2004
1330     **/

1331
1332/*
1333      if (_Optwhereclause2 != null) {
1334         ( (VariableValueOperations) vv).setFlag(true);
1335         _Optwhereclause2.setDefaultValues(vv);
1336         ( (VariableValueOperations) vv).setFlag(false);
1337      }
1338      _fromclause3.setTablesForInsertion(columnMapping, vv);
1339*/

1340   }
1341
1342   public TableDetails[] getTableDetails() throws DException {
1343      return finalTablePlan == null ? tableDetails
1344          : finalTablePlan.getTableDetails();
1345   }
1346
1347   public TableDetails[] getAllTableDetails() throws DException {
1348      return allTableDetails == null ?
1349          allTableDetails = _fromclause3.getAllTableDetails() :
1350          allTableDetails;
1351   }
1352
1353}
1354
Popular Tags