KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > daffodilwoods > daffodildb > server > sql99 > dql > iterator > table > GroupByIterator


1 package com.daffodilwoods.daffodildb.server.sql99.dql.iterator.table;
2
3 import java.util.*;
4 import com.daffodilwoods.daffodildb.client.*;
5 import com.daffodilwoods.daffodildb.server.sql99.common.*;
6 import com.daffodilwoods.daffodildb.server.sql99.dql.execution.*;
7 import com.daffodilwoods.daffodildb.server.sql99.dql.iterator.*;
8 import com.daffodilwoods.daffodildb.server.sql99.utils.*;
9 import com.daffodilwoods.daffodildb.utils.field.*;
10 import com.daffodilwoods.database.resource.*;
11 import com.daffodilwoods.database.utility.P;
12 import com.daffodilwoods.daffodildb.utils.field.FieldBase;
13 import com.daffodilwoods.daffodildb.server.sql99.common.ColumnDetails;
14 import com.daffodilwoods.daffodildb.utils.FieldUtility;
15 import com.daffodilwoods.daffodildb.utils.BufferRange;
16 import com.daffodilwoods.daffodildb.server.sql99.expression.ValueExpressionSuper;
17 import com.daffodilwoods.daffodildb.server.sql99.expression.valueexpression;
18 import com.daffodilwoods.daffodildb.server.serversystem._ServerSession;
19 import com.daffodilwoods.daffodildb.server.datasystem.indexsystem.TableKeyColumnInformation;
20
21 /**
22  * <p>Title: GroupByIterator </p>
23  * <p>Description: This Class handles the retrieval of records for queries
24  * having group by clause. The query with group by clause can also have
25  * aggregates (count,sum,min,max or/and avg). The purpose of Group By iterator
26  * is to derive different groups from the underlying iterator based on group by
27  * condition and to compute the results of aggregate-column corresponding to
28  * derived group. </p>
29  * <p>Copyright: Copyright (c) 2004</p>
30  * <p>Company: </p>
31  * @author not attributable
32  * @version 1.0
33  */

34
35 public class GroupByIterator extends BaseSingleIterator implements _Iterator, SimpleConstants {
36
37    /**
38     * Variable representing the given group by clause in select query.
39     */

40    private GroupByCondition groupByCondition;
41    /**
42     * Variable representing mapping of aggregate columns given in select
43     * query and its corresponding executable aggregate which is used to compute
44     * and retrieve the aggregate column value.
45     */

46    protected Object JavaDoc[][] mapping; //
47
/**
48     * Variable representing the navigation direction i.e. state is true when
49     * records are fetching in forward direction otherwise false.
50     */

51    protected int state; // FORWARD
52
/**
53     * Variable representing the state of iterator.
54     */

55    protected int status; // VALID/INVALID etc.
56
/**
57     * Variable representing the columns involved in group by clause.
58     */

59    private ColumnDetails[] columnDetails;
60    /**
61     * Variable representing the key column information of underlying iterator
62     * which is used to get a particular key of group by iterator.
63     */

64    protected _KeyColumnInformation[] keyColumnInformation;
65    /**
66     * Variable representing the tables involved in the group by query.
67     */

68    private TableDetails[] tables;
69
70    public Object JavaDoc[] objectToMove;
71
72    private _VariableValues variableValues;
73
74
75    private Object JavaDoc[] getObjectArray() throws DException{
76 if( keyColumnInformation ==null)
77        return null;
78      int len = keyColumnInformation.length;
79     FieldBase[] list = new FieldBase[len];
80      for(int i=0;i<len;i++){
81        int datatype = keyColumnInformation[i].getColumnDetails().getDatatype();
82        list[i] = FieldUtility.getField(datatype,null) ;
83      }
84      return list;
85    }
86
87    /**
88     * Initializes the variables with the given underlying iterator, condition
89     * and aggregate columns information. The constructor creates the aggregates
90     * mapping i.e. one time process for a given group by query.
91     * @param iterator underlying iterator on which group by is to perform.
92     * @param groupByCondition0 represents the given group by condition in select query
93     * @param aggregateColumnDetails0 given aggregate columns in select query
94     * @throws DException
95     */

96    public GroupByIterator(_Iterator iterator, GroupByCondition groupByCondition0, ColumnDetails[] aggregateColumnDetails0,_Reference[] aggregateColumnUnderlyingReferences0,_ServerSession serverSession) throws DException {
97      super(iterator);
98      status = INVALIDSTATE;
99      variableValues=new VariableValues(serverSession);
100      variableValues.setIterator(iterator);
101      groupByCondition = groupByCondition0;
102      if (aggregateColumnDetails0 != null) {
103        int len = aggregateColumnDetails0.length;
104        mapping = new Object JavaDoc[len][2];
105        for (int i = 0; i < len; i++) {
106          mapping[i][0] = aggregateColumnDetails0[i];
107          mapping[i][1] = aggregateColumnDetails0[i].getExecutable();
108        }
109      }
110      if (groupByCondition != null) {
111        columnDetails = groupByCondition.getColumnDetails();
112        keyColumnInformation = getKeyColumnInformations();
113        tables = iterator.getTableDetails();
114        Object JavaDoc[][] mapping = getMappingOfTableAndKey();
115        iterator.setKeyCount(mapping);
116      }
117      else {
118        keyColumnInformation = getKeyColumnInformations();
119      }
120      objectToMove = getObjectArray();
121     }
122
123    /**
124     * This method is responsible for retriving the mapping of table and number
125     * of columns involved in group by condition of corresponding table.
126     * @return a mapping of tables and number of columns given in group by clause.
127     * @throws DException
128     */

129    private Object JavaDoc[][] getMappingOfTableAndKey() throws DException {
130       ArrayList list = getListOfTables(columnDetails);
131       ArrayList mapping = new ArrayList(5);
132       while (list.size() != 0) {
133          int count = 1;
134          TableDetails table = (TableDetails) list.remove(0);
135          for (int i = 0; i < list.size(); i++) {
136             TableDetails table1 = (TableDetails) list.get(i);
137             if (table == table1) {
138                ++count;
139                list.remove(i);
140                --i;
141             }
142          }
143          mapping.add(new Object JavaDoc[] {table, new Integer JavaDoc(count)});
144       }
145       return (Object JavaDoc[][]) mapping.toArray(new Object JavaDoc[mapping.size()][2]);
146    }
147    /**
148     * This method is responsible for retriving list of tables
149     * corresponding to the columns involved in group by condition.
150     * @param columns columns given in group by condition of select query
151     * @return list of tables having columns in group by clause
152     * @throws DException
153     */

154    private ArrayList getListOfTables(ColumnDetails[] columns) throws DException {
155       ArrayList list = new ArrayList(5);
156       for (int i = 0, length = columnDetails.length; i < length; i++) {
157          list.add(columnDetails[i].getTable());
158       }
159       return list;
160    }
161
162    /**
163     * The following methods are used for navigation of group by iterator.
164     **/

165
166    /**
167     * This method is responsible for retriving the first record from the group
168     * by iterator. The purpose of this method is to identify the first group and
169     * to calculate the given aggregates corresponding to given aggregate columns.
170     * Records are retrieved from underlying iterator till they belongs to the same
171     * group. When first group starts, aggregate's results are initialized to their
172     * default values. Now, next records are fetched from underlying iterator,
173     * till they belong to same group and the values of these records are used in
174     * computation of aggregates for that group. At the end of group Underlying
175     * iterator is moved back to its last record of that group. Iterator is set
176     * to VALID state, if there is a valid record, otherwise it is set to AFTERLAST.
177     * direction flag is set to true (forward direction fetching).
178     * @return false if underlying iterator has no records, true otherwise.
179     * @throws DException
180     */

181    public boolean first() throws DException { //to change in the the last method also.....
182
if (iterator.first()) {
183          state = FORWARD; //State Forward Set as we are Doing fetching forward.
184
return (status = CheckForSameGroup() ? VALIDSTATE : AFTERLAST) == VALIDSTATE;
185       }else{
186         if (mapping != null) {
187            for (int i = 0; i < mapping.length; i++) {
188               ( (_Aggregate) mapping[i][1]).initialize();
189            }
190         }
191       }
192       status = AFTERLAST;
193       return false;
194    }
195
196    /**
197     * This method is responsible for giving next record corresponding to given
198     * query. This method performs the basic iterator's state corresponding
199     * functionality. For a valid state, next record is retrieved as follows -
200     * 1. If the fetching direction is backward it means the underlying iterator
201     * is at the first record of the current group of group by iterator. And for
202     * calculating next group, the records corresponding to this current group
203     * has to be skipped. Underlying iterator is set at the last record of the
204     * current group. (This is the state for forward direction fetching means
205     * underlying iterator is set at last record of previous group.)
206     * 2. Otherwise Next record is fetched from the underlying iterator, which
207     * starts next group, aggregates are initialized, next records are fetched
208     * from underlying iterator till records belongs to same next group. For each
209     * next record, given aggregate results are updated.
210     * 3. If underlying iterator has no records, return false.
211     * An exception is occured when previously fetch direction was backward and
212     * underlying iterator was at BEFORE FIRST state. Now we want to skip the
213     * group to get the next record. In this case exception occured and it is
214     * ignored because we dont have any need to skip the group when iterator is
215     * at BEFORE FIRST STATE.
216     * @return true if record found, false otherwise. This method also returns
217     * false if iterator state is AFTERLAST.
218     * @throws DException if underlying iterator is at invalid status.
219     */

220    public boolean next() throws DException {
221       switch (status) {
222          case INVALIDSTATE:
223             throw new DException("DSE4116", null);
224          case BEFOREFIRST:
225             return first();
226          case AFTERLAST:
227             return false;
228          default: {
229             if (state == BACKWARD) {
230                try {
231                   skipGroupForward();
232                } catch (DException checkDoc) {
233                   checkDoc.printStackTrace();
234                   /** @todo To Caught Invalid status as underlying iterator will be before first */
235                }
236             }
237             if (iterator.next()) {
238                state = FORWARD;
239                return (status = CheckForSameGroup() ? VALIDSTATE : AFTERLAST) == VALIDSTATE;
240             }
241             status = AFTERLAST;
242             return false;
243          }
244       }
245    }
246
247    /**
248     * This method is required when we've to retrieve the records in backward
249     * direction but previously direction was forward.Forward fetching leaves the
250     * underlying iterator at the last record of group. And for backward fetching,
251     * underlying iterator must be on the first record. so This method is
252     * responsible for setting the underlying iterator at the first record of
253     * current group.
254     * @throws DException
255     */

256
257    private void skipGroupPrevious() throws DException {
258       if (groupByCondition != null) {
259          groupByCondition.setPreviousState();
260       } while (groupByCondition == null || groupByCondition.compare()) {
261          if (!iterator.previous()) {
262             iterator.next();
263             return;
264          }
265       }
266       iterator.next();
267    }
268    /**
269     * This method is required when we've to retrieve the records in forward
270     * direction but previously direction was backward. Backward fetching leaves
271     * the underlying iterator at the first record of group. And for forward
272     * fetching, underlying iterator must be on the last record. so This method
273     * is responsible for setting the underlying iterator at the last record of
274     * current group.
275     * @throws DException
276     */

277    private void skipGroupForward() throws DException {
278       if (groupByCondition != null) {
279          groupByCondition.setPreviousState();
280       } while (groupByCondition == null || groupByCondition.compare()) {
281          if (!iterator.next()) {
282             iterator.previous();
283             return;
284          }
285       }
286       iterator.previous();
287
288    }
289
290    /**
291     * This method is responsible for giving previous record corresponding to given
292     * query. This method performs the basic iterator's state corresponding
293     * functionality. For a valid state, next record is retrieved as follows -
294     * 1. If the fetching direction is forward it means the underlying iterator
295     * is at the last record of the current group of group by iterator. And for
296     * calculating previous group, the records corresponding to this current group
297     * has to be skipped. Underlying iterator is set at the first record of the
298     * current group by navigating in backward direction. (This is the state for
299     * backward direction fetching means underlying iterator is set at first record
300     * of previous record group.)
301     * 2. Otherwise Previous record is fetched from the underlying iterator, which
302     * starts previous group, aggregates are initialized. Previous records are
303     * fetched from underlying iterator til records belongs to same previous group.
304     * For each previous record, given aggregate results are updated.
305     * 3. If underlying iterator has no records, return false.
306     * An exception is occured when previously fetch direction was forward and
307     * underlying iterator was at AFTER LAST state. Now we want to skip the
308     * group to get the previous record. In this case exception occured and it is
309     * ignored because we dont have any need to skip the group when iterator is
310     * at AFTER LAST STATE.
311     * @return true if record found, false otherwise. This method also returns
312     * false if iterator state is BEFORE FIRST.
313     * @throws DException if underlying iterator is at invalid status.
314
315     */

316    public boolean previous() throws com.daffodilwoods.database.resource.DException {
317       switch (status) {
318          case INVALIDSTATE:
319             throw new DException("DSE4117", null);
320          case BEFOREFIRST:
321             return false;
322          case AFTERLAST:
323             return last();
324          default: {
325             if (state == FORWARD) {
326                try {
327                   skipGroupPrevious();
328                } catch (DException E) { // This exception will come when we want to Navigate Backward and previously state was forward and status was after last.Now when we skipGroupPrevious it'll throw exception of invalid status.It means I've to reach on last and just compute previous group.And also if underlying iterator is before first and i give a call for next it'll now point to first record.
329
/** @todo To Caught Invalid status as underlying iterator will be after last */
330                }
331             }
332             if (iterator.previous()) {
333                state = BACKWARD;
334                return (status = CheckForSameGroupPrevious() ? VALIDSTATE : BEFOREFIRST) == VALIDSTATE;
335             }
336             status = BEFOREFIRST;
337             return false;
338          }
339       }
340    }
341
342    /**
343     * This method is responsible for retriving the last record from the group
344     * by iterator. The purpose of this method is to identify the last group and
345     * to calculate the given aggregates corresponding to given aggregate columns.
346     * Records are retrieved from underlying iterator till they belongs to the same
347     * group. When last group starts, aggregate's results are initialized to their
348     * default values. Now, previous records are fetched from underlying iterator,
349     * till they belong to same group and the values of these records are used in
350     * computation of aggregates for that group. At the end of group Underlying
351     * iterator is moved back to its first record of that group. Iterator is set
352     * to VALID state, if there is a valid record, otherwise it is set to BEFOREFIRST.
353     * direction flag is set to true (backward direction fetching).
354     * @return false if underlying iterator has no records, true otherwise.
355     * @throws DException
356     */

357    public boolean last() throws DException {
358       if (iterator.last()) {
359          state = BACKWARD; // State Forward Set as we are Doing fetching forward.
360
return (status = CheckForSameGroupPrevious() ? VALIDSTATE : BEFOREFIRST) == VALIDSTATE;
361       }else{
362         if (mapping != null) {
363           for (int i = 0; i < mapping.length; i++) {
364             ( (_Aggregate) mapping[i][1]).initialize();
365           }
366         }
367       }
368       status = BEFOREFIRST;
369       return false;
370    }
371
372    /**
373     * This method is responsible for the computation of given aggregates in the
374     * select query during the fetching in forward direction.
375     * 1. When a particular group starts, aggregate's result are initialized to
376     * their default values.
377     * 2. Next records are fetched from underlying iterator, till they belong to
378     * same group and the values of these records are used in computation of
379     * aggregates for that group.Underlying iterator is set to last record of the
380     * group by, to provide the values of group by columns for that group.
381     * @return true
382     * @throws DException
383     */

384    protected boolean CheckForSameGroup() throws DException {
385       int len = 0;
386       if (mapping != null) {
387          len = mapping.length;
388          for (int i = 0; i < len; i++) {
389             ( (_Aggregate) mapping[i][1]).initialize();
390          }
391       }
392       if (groupByCondition != null) {
393          groupByCondition.setPreviousState();
394       } while (groupByCondition == null || groupByCondition.compare()) {
395          int cnt = 0;
396          if (mapping != null) {
397          evaluateAggregates();
398          }
399          if (!iterator.next()) {
400             iterator.last();
401             return true;
402          }
403       }
404       iterator.previous();
405       return true;
406    }
407
408    /**
409     * This method is responsible for the computation of given aggregates in the
410     * select query during the fetching in backward direction.
411     * 1. When a particular group starts, aggregate's result are initialized to
412     * their default values.
413     * 2. Previous records are fetched from underlying iterator, till they belong to
414     * same group and the values of these records are used in computation of
415     * aggregates for that group. Underlying iterator is set to first record of the
416     * group by, to provide the values of group by columns for that group.
417     * @return true
418     * @throws DException
419     */

420    protected boolean CheckForSameGroupPrevious() throws DException {
421       int len = 0;
422       if (mapping != null) {
423          len = mapping.length;
424          for (int i = 0; i < len; i++) {
425             ( (_Aggregate) mapping[i][1]).initialize();
426          }
427       }
428       if (groupByCondition != null) {
429          groupByCondition.setPreviousState();
430       }
431
432       while (groupByCondition == null || groupByCondition.compare()) {
433          if (mapping != null) {
434             evaluateAggregates();
435          }
436          if (!iterator.previous()) {
437             iterator.first();
438             return true;
439          }
440       }
441       iterator.next();
442       return true;
443    }
444
445    /**
446     * This method is responsible to point to a particular record of the iterator.
447     * This method moves the underlying iterator at the keys passed. The underlying
448     * iterator will point to first record for the passed key. So aggregates are
449     * computed according to forward direction.
450     * @param keys represents the values of columns involved in groupby clause.
451     * @throws DException
452     */

453    public void move(Object JavaDoc keys) throws DException {
454        if (mapping != null && groupByCondition == null) {
455           first();
456           return;
457        }
458        /** @todo SUBJECT TO CHANGE */
459        iterator.move(keys);
460        switch (state) {
461           case FORWARD:
462
463              skipGroupPrevious();
464              CheckForSameGroup();
465              break;
466           case BACKWARD:
467             skipGroupForward();
468              CheckForSameGroupPrevious();
469              break;
470        }
471        status = VALIDSTATE;
472    }
473
474    /**
475     * This method retrives the key of a particular record. The key of Group by
476     * iterator is the values of the key columns which are in turn columns
477     * involved in group by.
478     * @return key of the record
479     * @throws DException
480     */

481    public Object JavaDoc getKey() throws DException {
482      if (keyColumnInformation == null)
483        return null;
484        int length = keyColumnInformation.length;
485        Object JavaDoc[] key = new Object JavaDoc[length];
486        for (int i = 0; i < length; i++) {
487          key[i] = iterator.getColumnValues(keyColumnInformation[i].
488                                            getColumnDetails());
489        }
490        return key;
491    }
492
493    /**
494     * The following methods are used for retrival of records from group by iterator.
495     * All retrival methods use the following logic.
496     * The retrival method checks the column type,if the column is aggregate functional
497     * column, result is retreived from the maintained mapping of aggregate columns.
498     * During the navigation of records, results of aggregate columns are computed,
499     * result can simply be obtained by calling getResult method of _Aggregate
500     * corresponding to aggregate column for which value is to be retrived.
501     * If column is not an aggregate column, it's value is retrived from
502     * underlying iterator. Since these columns can be grouped columns only,
503     * grouped columns values are same for each record for one group. Underlying
504     * iterator may be at first or last record.
505     **/

506
507    /**
508     * This method is used to retrieve the value of passed reference.
509     * @param references reference for which values are to be retrived.
510     * Reference may be column or parameter.
511     * @return NonShared FieldBases denoting the value of References. Non Shared
512     * FieldBases are those for which BufferRange is not shared with some other
513     * FieldBase.
514     * @throws DException
515     */

516    public Object JavaDoc getColumnValues(_Reference[] references) throws DException {
517
518       int len = references.length;
519       Object JavaDoc[] result = new Object JavaDoc[len];
520       outerLoop:for (int j = 0; j < len; j++) {
521          if (mapping != null) {
522             int length = mapping.length;
523             for (int i = 0; i < length; i++) {
524                if ( ( (ColumnDetails) mapping[i][0]).getColumn().trim().equalsIgnoreCase(references[j].getColumn().trim())) {
525                   result[j] = ( (_Aggregate) mapping[i][1]).getResult();
526                   continue outerLoop;
527                }
528             }
529          }
530
531          result[j] = ( (Object JavaDoc[]) iterator.getColumnValues(new _Reference[] {references[j]}))[0];
532       }
533       return result;
534    }
535
536
537    /**
538     * This method is responsible to retrieve the values of passed columns
539     * indexes from current record.
540     * @param parm1 column indexes corresponding to which values are to be retrieved.
541     * @return NonShared FieldBases denoting the value of References. Non Shared
542     * FieldBases are those for which BufferRange is not shared with some other
543     * FieldBase.
544     * @throws DException
545     */

546    public Object JavaDoc getColumnValues(int[] parm1) throws com.daffodilwoods.database.resource.DException {
547       return iterator.getColumnValues();
548    }
549
550    /**
551     * This method is responsible to retrieve complete record values.
552     * @return NonShared FieldBases denoting the values of all columns in query.
553     * Non Shared FieldBases are those for which BufferRange is not shared with
554     * some other FieldBase.
555     * @throws DException
556     */

557    public Object JavaDoc getColumnValues() throws DException {
558       ArrayList list = new ArrayList();
559       list.addAll(Arrays.asList( (Object JavaDoc[]) iterator.getColumnValues()));
560       return list.toArray(new Object JavaDoc[list.size()]);
561    }
562
563    /**
564     * This method is used to retrieve the value of passed reference.
565     * @param references reference for which value is to be retrived.
566     * Reference may be column or parameter.
567     * @return NonShared FieldBases denoting the value of References. Non Shared
568     * FieldBases are those for which BufferRange is not shared with some other
569     * FieldBase.
570     * @throws DException
571     */

572    public Object JavaDoc getColumnValues(_Reference references) throws DException {
573       Object JavaDoc result = null;
574       if (mapping != null) {
575          int length = mapping.length;
576          for (int i = 0; i < length; i++) {
577             if ( ( (ColumnDetails) mapping[i][0]).getColumn().trim().equalsIgnoreCase(references.getColumn().trim())) {
578                result = ( (_Aggregate) mapping[i][1]).getResult();
579                return result;
580             }
581          }
582       }
583       result = iterator.getColumnValues(references);
584       return result;
585    }
586
587    /**
588     * This method return the shared FieldBase for the passed reference. By Shared
589     * FieldBase we mean, BufferRange of FieldBase is shared with other FieldBase
590     * objects.
591     * @param references reference for which value is to be retrived
592     * @return shared field base correspondition to passed column reference
593     * @throws DException
594     */

595
596    public FieldBase field(_Reference references) throws com.daffodilwoods.database.resource.DException {
597       FieldBase result = null;
598       if (mapping != null) {
599          int length = mapping.length;
600          for (int i = 0; i < length; i++) {
601             if ( ( (ColumnDetails) mapping[i][0]).getColumn().trim().equalsIgnoreCase(references.getColumn().trim())) {
602                result = (FieldBase) ( (_Aggregate) mapping[i][1]).getResult();
603                return result;
604             }
605          }
606       }
607       result = iterator.field(references);
608       return result;
609    }
610
611    /**
612     * This method return the shared FieldBase for the passed reference. By Shared
613     * FieldBase we mean, BufferRange of FieldBase is shared with other FieldBase
614     * objects.
615     * @param references for which values are to be retrived
616     * @return shared field bases correspondition to passed column references
617     * @throws com.daffodilwoods.database.resource.DException
618     */

619    public FieldBase[] fields(_Reference[] references) throws com.daffodilwoods.database.resource.DException {
620       int len = references.length;
621       FieldBase[] result = new FieldBase[len];
622       outerLoop:for (int j = 0; j < len; j++) {
623          if (mapping != null) {
624             int length = mapping.length;
625             for (int i = 0; i < length; i++) {
626                if ( ( (ColumnDetails) mapping[i][0]).getColumn().trim().equalsIgnoreCase(references[j].getColumn().trim())) {
627                   result[j] = (FieldBase) ( (_Aggregate) mapping[i][1]).getResult();
628                   continue outerLoop;
629                }
630             }
631          }
632          result[j] = ( (FieldBase[]) iterator.fields(new _Reference[] {references[j]}))[0];
633       }
634       return result;
635    }
636
637    public FieldBase[] fields(int[] columns) throws com.daffodilwoods.database.resource.DException {
638       throw new java.lang.UnsupportedOperationException JavaDoc("Method fields() not yet implemented.");
639    }
640
641    /**
642     * END OF RETRIEVAL METHODS
643     */

644
645    /**
646     * This method is responsible for retrival of tables involved in the underlying
647     * iterator.
648     * @return tables involved in select query
649     * @throws com.daffodilwoods.database.resource.DException
650     */

651    public TableDetails[] getTableDetails() throws com.daffodilwoods.database.resource.DException {
652       return tables == null ? iterator.getTableDetails() : tables;
653    }
654
655
656   public byte[] getByteKey() throws DException {
657     int length = keyColumnInformation.length;
658     int resultantLength =0;
659     ArrayList KeyInfo = new ArrayList(5);
660     for(int i=0;i<length;i++){
661       Object JavaDoc key = iterator.getColumnValues(keyColumnInformation[i].
662                                             getColumnDetails());
663       FieldBase fbKey1 = (FieldBase) key;
664    /*Done by vibha on 12-08-2004 to solve NP- bug no 11631*/
665       if (fbKey1.isNull()) {
666         KeyInfo.add(null);
667       }
668       else {
669         byte[] columnValues = fbKey1.getBufferRange().getBytes();
670         KeyInfo.add(columnValues);
671         resultantLength += columnValues.length;
672       }
673     }
674     return getResultantKeyInfo(resultantLength,KeyInfo);
675   }
676
677   private byte[] getResultantKeyInfo(int resultantLen,ArrayList KeyInfo){
678     byte[] resultantKeyInfo = new byte[resultantLen+KeyInfo.size()];
679   for(int i=0,j=0;i<KeyInfo.size();i++){
680     byte[] columnValues = (byte[]) KeyInfo.get(i);
681     /*Done by vibha on 12-08-2004 to solve NP- bug no 11631*/
682     if (columnValues == null) {
683       resultantKeyInfo[j] = 0;
684       j += 1;
685     }
686     else {
687       resultantKeyInfo[j] = (byte) columnValues.length;
688       System.arraycopy(columnValues, 0, resultantKeyInfo, j + 1,
689                        columnValues.length);
690       j += columnValues.length + 1;
691     }
692   }
693   return resultantKeyInfo;
694
695   }
696
697   private byte[] getByte(int index, int lengthOfKey) throws DException {
698     int length = 0;
699     byte[] resultant = new byte[0];
700     byte[] temp = null;
701     for (int i = index; i < index + lengthOfKey; i++) {
702       FieldBase fb = iterator.field(keyColumnInformation[i].getColumnDetails());
703       byte[] keys = fb.getBufferRange().getBytes();
704       length += keys.length;
705       temp = new byte[resultant.length];
706       System.arraycopy(resultant, 0, temp, 0, temp.length);
707       resultant = new byte[length];
708       System.arraycopy(temp, 0, resultant, 0, temp.length);
709       System.arraycopy(keys, 0, resultant, temp.length, keys.length);
710
711     }
712     return resultant;
713
714   }
715
716
717   public void moveByteKey(byte[] key) throws DException {
718     for(int i=0,j=0;i<key.length && j< objectToMove.length ;){
719 /*dst Done by Sandeep Kadiyan to solve Bug --11909 on 15/1/2005 */
720       BufferRange bf = key[i]==0?new BufferRange(true):new BufferRange(key,i+1,key[i]);
721       ((FieldBase)objectToMove[j]).setBufferRange(bf);
722       i+=key[i]+1;
723       j++;
724     }
725    try {
726       move(objectToMove);
727    }
728    catch (DException ex) {
729       throw ex;
730    }
731   }
732
733
734    /**
735     * This method is responsible to display the executionPlan of a Select Query.
736     * @return _ExecutionPlan
737     * @throws DException
738     */

739    public _ExecutionPlan getExecutionPlan() throws DException {
740       _ExecutionPlan plan = iterator.getExecutionPlan();
741       _ExecutionPlan cplans[] = plan == null ? null : new _ExecutionPlan[] {plan};
742       String JavaDoc aggColumns = getAggerigateColumns();
743       return new ExecutionPlan("GroupByIterator", cplans, "" + groupByCondition, null, aggColumns);
744    }
745
746    /**
747     * This method is responsible to display the iterators hierarchy of a Select Query.
748     * @return ExecutionPlanForBrowser
749     * @throws DException
750     */

751    public ExecutionPlanForBrowser getExecutionPlanForBrowser() throws DException {
752       ExecutionPlanForBrowser plan = iterator.getExecutionPlanForBrowser();
753       ExecutionPlanForBrowser cplans[] = plan == null ? null : new ExecutionPlanForBrowser[] {plan};
754       String JavaDoc aggColumns = getAggerigateColumns();
755       return new ExecutionPlanForBrowser("Group By " + aggColumns, "GroupByIterator", cplans, "" + groupByCondition, null, null);
756    }
757
758    /**
759     * This method is required to release the resources for e.g. comaparator,
760     * that may be associated with particular parameters given query.
761     * @throws DException
762     */

763    public void releaseResource() throws DException {
764       iterator.releaseResource();
765       if (mapping != null) {
766          for (int i = 0; i < mapping.length; i++) {
767             _Aggregate aggregate = (_Aggregate) mapping[i][1];
768             aggregate.releaseResource();
769          }
770       }
771    }
772
773    /**
774     * Returns the key column information for the column included in the group by
775     * clause.
776     * @return key column information of columns given in group by clause
777     * @throws DException
778     */

779    public _KeyColumnInformation[] getKeyColumnInformations() throws DException {
780
781      if (columnDetails == null)
782        return iterator.getKeyColumnInformations();
783        _KeyColumnInformation[] key = new _KeyColumnInformation[columnDetails.
784            length];
785        for (int i = 0; i < columnDetails.length; i++) {
786          key[i] = new TableKeyColumnInformation(columnDetails[i], false);
787        }
788        return key;
789
790    }
791
792    /**
793
794      if (keyColumnInformation == null) {
795          keyColumnInformation = iterator.getKeyColumnInformations();
796          if (columnDetails == null) {
797             return keyColumnInformation;
798          }
799          int length = keyColumnInformation.length;
800          ArrayList aList = new ArrayList(length);
801          for (int i = 0; i < length; i++) {
802             ColumnDetails cd = keyColumnInformation[i].getColumnDetails();
803             if (matched(cd)) {
804                aList.add(keyColumnInformation[i]);
805             }
806          }
807          keyColumnInformation = (_KeyColumnInformation[]) aList.toArray(new _KeyColumnInformation[aList.size()]);
808       }
809       return keyColumnInformation;
810
811    }**/

812
813    /**
814     * Checks whether the passed column is present in group by clause or not.
815     * @param cd column to be find in group by clause
816     * @return true if passed column is present in group by clause, false
817     * otherwise.
818     * @throws DException
819     */

820    private boolean matched(ColumnDetails cd) throws DException {
821       for (int i = 0, length = columnDetails.length; i < length; i++) {
822         /*Work Done regarding bug no . 12663 -- Manoj Kr. Dec 7 , 2004 */
823          if (columnDetails[i].getTable() == cd.getTable() && columnDetails[i].getAppropriateColumn().equalsIgnoreCase(cd.getAppropriateColumn())) {
824             return true;
825          }
826       }
827       return false;
828    }
829
830    /**
831     *This method assists to display the PLAN of a Query.
832     * @return aggregate column details
833     * @throws DException
834     */

835    private String JavaDoc getAggerigateColumns() throws DException {
836       if (mapping == null || mapping.length == 0) {
837          return null;
838       }
839       String JavaDoc name = "";
840       int length = mapping.length - 1, i = 0;
841       for (; i < length; i++) {
842          name += "Aggregate[" + i + "] = " + mapping[i][0] + ",";
843       }
844       name += "Aggregate[" + i + "] =" + mapping[i][0];
845       return name;
846    }
847
848    /**
849     * This iterator can not be optimised by top level iterator.
850     * Since the passed column can be a aggregate column, for an aggregate
851     * column, it is required to compute the aggregate function value using
852     * the records belonging to that particular group.
853     * @param column aggregate/simple column of a group by query
854     * @return Group By iterator
855     * @throws com.daffodilwoods.database.resource.DException
856     */

857    public _Iterator getBaseIterator(ColumnDetails column) throws com.daffodilwoods.database.resource.DException {
858       return this;
859    }
860
861    /**
862     * Sets the values of references that may belong to underlying iterator
863     * or to group by condition.
864     * @param references references of which values to be set into the iterator
865     * @param values values to be set into the iterator
866     * @param priority this parameter is not used
867     * @throws DException
868     */

869    public void setConditionVariableValue(_Reference[] references, Object JavaDoc[] values, int priority) throws DException {
870      if(underlyingRef!=null){
871        references = GeneralPurposeStaticClass.getJointReferences(references,underlyingRef);
872        values = GeneralPurposeStaticClass.getJointValues(this, values,underlyingRef.length);
873      }
874      variableValues. addReferences(references);
875      variableValues.setConditionVariableValue(references, values, priority);
876
877      iterator.setConditionVariableValue(references, values, priority);
878      if (groupByCondition != null) {
879        groupByCondition.setConditionVariableValue(references, values, priority);
880      }
881    }
882
883
884    /**
885     * The following methods of this class are used a intermediate in the
886     * iterator hierarchy. These methods simply transfer the call to the
887     * underlying iterator with the same arguments.
888     */

889
890    public void setKeyCount(Object JavaDoc[][] tableAndKeyCount) throws DException {
891    }
892
893    public Object JavaDoc[][] getFunctionalColumnMapping() throws DException {
894       return iterator.getFunctionalColumnMapping();
895    }
896
897
898    public String JavaDoc toString() {
899       String JavaDoc str = "GROUPBYITERATOR";
900       try {
901          if (iterator != null) {
902             str += "[" + iterator.toString() + "]";
903          }
904       } catch (Exception JavaDoc e) {
905          e.printStackTrace();
906       }
907       return str;
908    }
909    protected void evaluateAggregates() throws DException{
910     try {
911        int len = mapping.length;
912        Object JavaDoc obj[] = new Object JavaDoc[len];
913        for (int i = 0; i < len; i++) {
914           valueexpression ve=( (_Aggregate) mapping[i][1]).getValueExpression();
915           if(ve!=null){
916             obj[i] = ve.run(variableValues);
917           }else
918             obj[i]=null;
919        }
920        for (int i = 0; i < len; i++) {
921           ( (_Aggregate) mapping[i][1]).addRecord(obj[i]);
922        }
923     } catch (DException ex) {
924        if(ex.getDseCode().equalsIgnoreCase("DSE2004"))
925           return;
926        throw ex;
927     }
928  }
929 }
930
Popular Tags