KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > daffodilwoods > daffodildb > server > sql99 > dql > iterator > set > UnionDistinctIterator


1 package com.daffodilwoods.daffodildb.server.sql99.dql.iterator.set;
2
3 import com.daffodilwoods.daffodildb.client.*;
4 import com.daffodilwoods.daffodildb.server.sql99.common.*;
5 import com.daffodilwoods.daffodildb.server.sql99.dql.iterator.*;
6 import com.daffodilwoods.daffodildb.server.sql99.utils.*;
7 import com.daffodilwoods.daffodildb.utils.comparator.*;
8 import com.daffodilwoods.database.resource.*;
9 import com.daffodilwoods.database.utility.P;
10
11 /**
12  * <p>Title: UnionDistinctIterator </p>
13  * <p>This class is used for retrieval of records from a query having UNION
14  * DISTINCT set operator. UNION DISTINCT set operator returns all the records
15  * from both of the underlying iterators except duplicate records. In UNION
16  * DISTINCT Iterator, data of both underlying itertors is sorted, values of
17  * selected columns from both iterators are compared and duplicate values are
18  * skipped while navigating either of the iterator in any of the direction. </p>
19  *
20  * <p>This class is meant for merging and retrieval of the combined result for
21  * <UNION DISTINCT Clause> set Operator . In UNION DISTINCT, All records from
22  * both the iterator 'll be retrieved taking no duplicate record. A flag called
23  * changeInDirectionOfNavigation is also used here in order to handle any reverse
24  * iteration, i.e calling next after previous or calling previous after next method.</p>
25  * <p>Copyright: Copyright (c) 2003</p>
26  * <p>Company: </p>
27  * @author unascribed
28  * @version 1.0
29  */

30 public class UnionDistinctIterator extends UnionAllOrderedIterator {
31
32   /**
33    * The comparator that is used to compare one set of values of selected
34    * columns from left iterator with another set of values from same iterator.
35    */

36   private SuperComparator leftComparator;
37   /**
38    * The comparator that is used to compare one set of values of selected
39    * columns from right iterator with another set of values from same iterator.
40    */

41   private SuperComparator rightComparator;
42
43   /*statetToSet is the state that is set.*/
44   private int[] stateToSet = {FIRSTISCURRENT,FIRSTISCURRENT,BOTHHAVESAMEDATA,SECONDISCURRENT,SECONDISCURRENT};
45
46    /**
47     * A public constructor, that takes four arguments, two are left and right iterators, and
48     * other two are left and right side selected column References. A state is also maintained,
49     * that specifies the current status of the current level iterator(this).
50     *
51     * The State INVALIDSTATE means iterator is not aligned properly and needs to be aligned
52     * before doing any further operations.
53     *
54     * The State VALIDSTATE means iterator is aligned properly and can be moved next()/ previous()
55     * as well as values can also be retrieved
56     *
57     * The State BEFOREFIRST means, iterator has reached before the first record or there is no record in the result set.
58     * Iterator is not aligned properly and needs to be aligned through calling first()/ last() before doing any further operations.
59     *
60     * The State AFTERLAST means, iterator has reached after the last record or there is no record in the result set.
61     * Iterator is not aligned properly and needs to be aligned through calling first()/ last() before doing any further operations.
62     *
63     * The State FIRSTISCURRENT means, left iterator is the current iterator and is ready to provide the value for the current row.
64     *
65     * The State SECONDISCURRENT means, right iterator is the current iterator and is ready to provide the value for the current row.
66     *
67     * The State BOTHHAVESAMEDATA means, that both the left and right iterator have the same data
68     *
69     * @param leftIterator0
70     * @param rightIterator0
71     * @param leftColumnReferences0
72     * @param rightColumnReferences0
73     */

74    public UnionDistinctIterator(_Iterator leftIterator, _Iterator rightIterator, _Reference[] leftColumnReferences, _Reference[] rightColumnReferences, SuperComparator comparator0, int[] appropriateDataTypes, int[] appropriateSizes, _Reference[] orderLeftCD0, _Reference[] orderRightCD0, SuperComparator leftComparator0, SuperComparator rightComparator0) throws DException {
75       super(leftIterator, rightIterator, leftColumnReferences, rightColumnReferences, comparator0, appropriateDataTypes, appropriateSizes, orderLeftCD0, orderRightCD0);
76       leftComparator = leftComparator0;
77       rightComparator = rightComparator0;
78    }
79
80    /**
81     * This method is responsible for retriving first record of Union Iterator.
82     * First record is retrived from first and second iterator and a flag is
83     * maintained that represents that whether first or second iterator is
84     * CURRENT iterator (Iterator for which, values of selected columns is
85     * smaller than that of other iterator). For equal values, state is set
86     * to BOTHHAVESAMEDATA. If either of the iterator has no data, flag is
87     * initialized to ONLYFIRSTHASDATA or ONLYSECONDHASDATA accordingly.
88     *
89     * DETAILED DOCUMENTATION
90     *
91     * This method aligns the iterator to the first valid record.
92     * ALGO :::::
93     * the direction flag is set to FORWARD
94     * calls the first of both the iterators
95     * if both first are true then
96     * compare the values
97     * the one with the smaller value is set as the current iterator.
98     * if the only one of them is true then the state is set as ONLYFIRSTHASDATA or ONLYSECONDHASDATA according to which is current
99     * if neither is true then the state is set to AFTERLAST.
100     * it returns true if the the state is not AFTERLAST.
101     *
102     * @return true if either of the iterator has record, false, if none of the
103     * iterator has records.
104     * @throws com.daffodilwoods.database.resource.DException
105     */

106    public boolean first() throws com.daffodilwoods.database.resource.DException {
107       direction = FORWARD;
108       boolean leftFlag = leftIterator.first();
109       boolean rightFlag = rightIterator.first();
110
111       state = leftFlag ? rightFlag ? getState(compare(leftIterator.getColumnValues(orderLeftCD), rightIterator.getColumnValues(orderRightCD)))
112           : ONLYFIRSTHAVEDATA
113           : rightFlag ? ONLYSECONDHAVEDATA : AFTERLAST;
114       /*Done by vibha to solve bug no 11896 */
115       return state != AFTERLAST;
116    }
117
118    /**
119     * This method is responsible for retriving last record of Union Iterator.
120     * Last record is retrived from first and second iterator and a flag is
121     * maintained that represents that whether first or second iterator is
122     * CURRENT iterator (Iterator for which, values of selected columns is
123     * larger than that of other iterator). For equal values, state is set
124     * to BOTHHAVESAMEDATA. If either of the iterator has no data, flag is
125     * initialized to ONLYFIRSTHASDATA or ONLYSECONDHASDATA accordingly.
126     *
127     * DETAILED DOCUMENTATION
128     *
129     * This method aligns the iterator to the last valid record.
130     * ALGO:::
131     * it calls the last of both iterator
132     * if both are true then
133     * compare the values the one with the
134     * larger value is set as current.
135     * else if only one is true then the state is set as ONLYFIRSTHASDATA or ONLYRIGHTHASDATA
136     * if neither is true then set the state as BEFOREFIRST
137     * returns false if the state is BEFOREFIRST.
138     * @return true if either of the iterator has record, false, if none of the
139     * iterator has records.
140     * @throws com.daffodilwoods.database.resource.DException
141     */

142    public boolean last() throws com.daffodilwoods.database.resource.DException {
143       direction = BACKWARD;
144       boolean leftFlag = leftIterator.last();
145       boolean rightFlag = rightIterator.last();
146    state = leftFlag ? rightFlag ? getState(-compare(leftIterator.getColumnValues(orderLeftCD), rightIterator.getColumnValues(orderRightCD)) )
147           : ONLYFIRSTHAVEDATA
148           : rightFlag ? ONLYSECONDHAVEDATA : BEFOREFIRST;
149
150       return state != BEFOREFIRST;
151    }
152
153    /**
154     * This method is responsible for retriving next record of Union Iterator.
155     * 1. If the state denotes that one of the iterator is current. Next distinct
156     * record is retrived from CURRENT iterator. Goto 3.
157     * 2. If the state is BOTHHAVESAMEDATA, Next distinct record is retrived from
158     * both of the underlying iterators. Goto 3
159     * 3. Compare the values of selected columns, Make one of iterator to CURRENT,
160     * which has smaller values of selected columns as compared to that of other
161     * iterator and update the state acc. to compare result.
162     * 4. If state is ONLYFIRSTHASDATA or ONLYSECONDHASDATA it means only one of
163     * the iterator has data that must be navigated in forward direction to
164     * retrieve next distinct record.
165     *
166     * For forward fetching after backward fetching (if last or previous method
167     * has called before call to next method), special handing has been done.
168     * Both underlying iterators are navigated in such a way that produce state
169     * of both underlying iterators as same as that of before call to backward
170     * fetching method (last or previous method). In backward fetching, records
171     * from the iterator having larger values of selected columns are returned
172     * first, if any one of the iterator has no records, it's last record's values
173     * are compared with that of the selected column values of the another iterator.
174     * Larger Values must be returned first. Hence, the iterator having smaller
175     * values is navigated back(next method called) to its previous state. Thus,
176     * maintaining the previous state of both underlying iterators and returning
177     * the appropriate selected columns values.
178     *
179     * DETAILED DOCUMENTATION
180     *
181     * This method aligns the iterator to the next distinct record.
182     * Cases that involve mixed fetching i.e. next after previous are
183     * handled differently as it is necessary for the state to be restored to the
184     * state it was in.
185     * ALGO:::
186     * if the state is
187     * INVALIDSTATE :
188     * throw exception
189     * BEFOREFIRST :
190     * call first to align the iterator to the first record
191     * AFTERLAST
192     * return false as there are no valid records left.
193     * ONLYFIRSTHASDATA :
194     * if the direction of navigation is BACKWARD i.e. it is a case of mixed fetching.
195     * call the iteratePositiveAfterNegativeWhenOneHasData method
196     * else
197     * set the direction flag = FORWARD.
198     * call the moveForward method with the left iterator i.e. aligns the left iterator to the next distinct record.
199     * ONLYSECONDHASDATA:
200     * same as the above case.
201     * FIRSTISCURRENT :
202     * if the direction is backward i.e. mixed fetching
203     * then call the iteratePositiveAfterNegativeWhenOneIsCurrent method
204     * else
205     * call the iteratePositive method.
206     * SECONDISCURRENT :
207     * same as the above case.
208     * BOTHHAVESAMEDATA :
209     * if direction is backward then
210     * call the iteratePositiveAfterNegativeWhenBothHaveSameData method.
211     * else
212     * call the iteratePositiveWhenBoth method.
213     *
214     * @return true if either of the iterator has more distinct record in
215     * same forward navigation, false, otherwise.
216     * @throws com.daffodilwoods.database.resource.DException
217     */

218    public boolean next() throws com.daffodilwoods.database.resource.DException {
219      switch (state) {
220          case INVALIDSTATE:
221             throw new DException("DSE4116", null);
222          case BEFOREFIRST:
223             return first();
224          case AFTERLAST:
225             return false;
226          case ONLYFIRSTHAVEDATA:
227             if (direction == BACKWARD) {
228                return iteratePositiveAfterNegativeWhenOneHasData(leftIterator, rightIterator, orderLeftCD, orderRightCD, 1);
229             }
230             direction = FORWARD;
231             Object JavaDoc val = leftIterator.getColumnValues(orderLeftCD);
232             boolean flag = moveForward(leftIterator, val, orderLeftCD, 1);
233             state = flag ? state : AFTERLAST;
234             return flag;
235          case ONLYSECONDHAVEDATA:
236             if (direction == BACKWARD) {
237             return iteratePositiveAfterNegativeWhenOneHasData(rightIterator, leftIterator, orderRightCD, orderLeftCD, -1);
238             }
239             direction = FORWARD;
240             Object JavaDoc val1 = rightIterator.getColumnValues(orderRightCD);
241             boolean flag1 = moveForward(rightIterator, val1, orderRightCD, -1);
242             state = flag1 ? state : AFTERLAST;
243             return flag1;
244          case FIRSTISCURRENT:
245             if (direction == BACKWARD) {
246                return iteratePositiveAfterNegativeWhenOneIsCurrent(leftIterator, rightIterator, orderLeftCD, orderRightCD, 1);
247             }
248             return iteratePositive(leftIterator, rightIterator, 1, orderLeftCD, orderRightCD);
249          case SECONDISCURRENT:
250             if (direction == BACKWARD) {
251                return iteratePositiveAfterNegativeWhenOneIsCurrent(rightIterator, leftIterator, orderRightCD, orderLeftCD, -1);
252             }
253             return iteratePositive(rightIterator, leftIterator, -1, orderRightCD, orderLeftCD);
254          case BOTHHAVESAMEDATA:
255             if (direction == BACKWARD) {
256                return iteratePositiveAfterNegativeWhenBothHaveSameData(leftIterator, rightIterator, orderLeftCD, orderRightCD, 1);
257             }
258             return iteratePositiveWhenBoth();
259       }
260       return false;
261    }
262
263    /**
264     * This method is responsible to navigate one of the underlying iterator in
265     * forward direction to next distinct record, when both of the underlying
266     * iterators have data but one of the iterator is current. The purpose of
267     * this method is to navigate current iterator in forward direction to next
268     * distinct record. If there are no distinct records in current iterator,
269     * state is set to ONLYFIRSTHASDATA or ONLYSECONDHASDATA accordingly.
270     *
271     * DETAILED DOCUMENTAION
272     *
273     * This method is called by the next method when the state is either FIRSTISCURRENT or SECONDISCURRENT and it is not the case of mixed fetching
274     * Algo ::::::
275     * First the direction flag is changed set to FORWARD
276     * calls the moveForward with the currentIterator i.e. align the current iterator to the next distinct record
277     * if we cannot find any more disticnt record then
278     * state is set as ONLYSECONDHASDATA or ONLYFIRSTHASDATA according to which is current
279     * else
280     * we compare the values pointed to by both the iterators the one with the smaller value is set as current.
281     * @throws DException
282     * @usage assistance in next method
283     * @param firstIterator current iterator
284     * @param secondIterator other iterator which is not current
285     * @param reverse {1 or -1} 1 when left iterator is current, -1 when
286     * right iterator is current.
287     * @param firstReferences given selected columns of current iterator
288     * @param secondReferences given selected columns of other iterator
289     * @return TRUE
290     */

291    private boolean iteratePositive(_Iterator currentIterator, _Iterator otherIterator, int reverse, _Reference[] currentReferences, _Reference[] otherReferences) throws DException {
292       direction = FORWARD;
293       Object JavaDoc toCompare = currentIterator.getColumnValues(currentReferences);
294       boolean flag = moveForward(currentIterator, toCompare, currentReferences, reverse);
295       if (!flag) {
296          state = reverse == 1 ? ONLYSECONDHAVEDATA : ONLYFIRSTHAVEDATA;
297          return true;
298       }
299       Object JavaDoc first = currentIterator.getColumnValues(currentReferences);
300       Object JavaDoc second = otherIterator.getColumnValues(otherReferences);
301       state = reverse == 1 ? getState(compare(first, second)) : getState(compare(second, first));
302       return true;
303    }
304
305    /**
306     * This method is responsible to navigate current underlying iterator in
307     * forward direction to distinct record. Selected column values of next record
308     * from current iterator are compared with that of other iterator. Iterator
309     * with smaller values is made as Current Iterator. If there are no records
310     * in current iterator, state is set to ONLYFIRSTHASDATA or ONLYSECONDHASDATA
311     * accordingly.
312     *
313     * DETAILED DOCUMENTAION
314     *
315     * this method is called by next when the state is BOTHHAVESAMEDATA and it not a case of
316     * mixed fetching
317     * ALGO::::
318     * the direction flag is set as FORWARD
319     * then we call the moveForward for both the iterators i.e. both are move to the next distinct record
320     * if current iterator's moveForward is true
321     * if the moveForward of the other iterator is true then
322     * compare the data of the two iterators then
323     * if the data are the same then
324     * state is set to BOTHHAVESAMEDATA
325     * else if the iterator with the smaller value is set as current
326     * else
327     * state is set as ONLYFIRSTHAVEDATA
328     * else i.e. the moveForward() of the current iterator is not true
329     * if the moveForward() of the other iterator is true then
330     * state is set as ONLYSECONDHAVEDATA
331     * else ie. neither of the two is true then
332     * state is set as AFTERLAST
333     *
334     * @return
335     * @throws DException
336     */

337    private boolean iteratePositiveWhenBoth() throws DException {
338       direction = FORWARD;
339       boolean flag1 = moveForward(leftIterator, leftIterator.getColumnValues(orderLeftCD), orderLeftCD, 1);
340       boolean flag2 = moveForward(rightIterator, rightIterator.getColumnValues(orderRightCD), orderRightCD, -1);
341       if (flag1) {
342          if (flag2) {
343             int cmp = compare(leftIterator.getColumnValues(orderLeftCD), rightIterator.getColumnValues(orderRightCD));
344
345             state = cmp == 0 ? BOTHHAVESAMEDATA : cmp < 0 ? FIRSTISCURRENT : SECONDISCURRENT;
346          } else {
347             state = ONLYFIRSTHAVEDATA;
348          }
349       } else {
350          if (flag2) {
351             state = ONLYSECONDHAVEDATA;
352          } else {
353             state = AFTERLAST;
354          }
355       }
356       return state != AFTERLAST;
357    }
358
359    /**
360     * This method is called by next in the case of mixed fetching when next
361     * method is called after previous method and state of iterator corresponds
362     * to case when only one of the iterator has data. Other iterator's selected
363     * column values of first record will be checked with that of next distinct
364     * record of current iterator. If the other iterator's first record will have
365     * smaller values these values must be retruned first, hence, it is made as
366     * current iterator and current iterator is navigated revert back to previous
367     * state, otherwise, state remains to ONEISCURRENT (FIRST or SECOND same as
368     * before) and other iterator is set before first.
369     *
370     * DETAILED DOCUMENTATION
371     *
372     * this method is called by next in the case when only one of the iterator has data.
373     * ALGO ::::
374     * calls the moveForward method with the current iterator so the current iterator aligns itself to
375     * next record
376     * calls the first of the other iterator's first
377     * if both are true then
378     * compares the values of the two iterators
379     * if both are equal then
380     * it sets the state = BOTHHAVESAMEDATA.
381     * else
382     * the iterator with the smaller value is set as current and the previous of the other iterator is called
383     * if only the first of the other iterator is true then
384     * calls the last of the current iterator and the other iterator is set as current.
385     * if neither is true then the state is set as AFTERLAST
386     * @usage assistance in next method when fetching direction
387     * changes from backward to forward
388     * @param currentIterator current iterator
389     * @param otherIterator other iterator which is not current
390     * @param currentReferences given selected columns of current iterator
391     * @param otherReferences given selected columns of other iterator
392     * @param reverse true if left iterator is has data, false when
393     * right iterator has data
394     * @return FALSE if current iterator has no more records, true otherwise.
395     * @throws DException
396     */

397    private boolean iteratePositiveAfterNegativeWhenOneHasData(_Iterator currentIterator, _Iterator otherIterator, _Reference[] currentReferences, _Reference[] otherReferences, int reverse) throws DException {
398       boolean currentNext = moveForward(currentIterator, currentIterator.getColumnValues(currentReferences), currentReferences, reverse);
399       boolean otherFirst = otherIterator.first();
400       if (currentNext && otherFirst) {
401          Object JavaDoc currentObject = currentIterator.getColumnValues(currentReferences);
402          Object JavaDoc otherObject = otherIterator.getColumnValues(otherReferences);
403          int cmp = compare(currentObject, otherObject);
404          if (cmp == 0) {
405             state = BOTHHAVESAMEDATA;
406          } else if (cmp > 0) {
407             state = state == ONLYSECONDHAVEDATA ? FIRSTISCURRENT
408                 : state == ONLYFIRSTHAVEDATA ? SECONDISCURRENT : state;
409             currentIterator.previous();
410
411           } else {
412             otherIterator.previous();
413          }
414       } else if (currentNext) {
415       } else if (otherFirst) {
416          currentIterator.last();
417          state = state == ONLYSECONDHAVEDATA ? FIRSTISCURRENT
418              : state == ONLYFIRSTHAVEDATA ? SECONDISCURRENT : state;
419       } else {
420          state = AFTERLAST;
421          return false;
422       }
423       return true;
424    }
425
426    /**
427     * This method is called by next method when the state is FIRSTISCURRENT and
428     * previously fetching direction was backward (last or previous called).
429     * Next distinct record is retrieved from both of the underlying iterator.
430     * If both values are same, state is set to BOTHHAVESAMEDATA. Otherwise,
431     * The previous of underlying iterator is called which has larger values of
432     * selected columns, since larger values will be returned in the next call
433     * of next method.
434     *
435     * DETAILED DOCUMENTATION
436     *
437     * this method is called by next () when the state is either FIRSTISCURRENT or SECONDISCURRENT
438     * ALGO::::
439     * it calls the moveForward method in order to align the current iterator to the next disticnt record
440     * it calls the moveForward method in order to align the other iterator to the next distinct record
441     * if both are true then
442     * we compare the values of the records of the two iterators
443     * if the values are equal then
444     * state is set as BOTHHAVESAMEDATA.
445     * else if the current iterator has a larger value then
446     * the other iterator is set as current and the previous of the current iterator.
447     * else
448     * the state remains the same and the previous of the other iterator is called
449     * else if only the moveForward of the current is true
450     * then the last of the other iterator is called
451     * else if the moveForward of the other iterator is true then
452     * the last of the current is called and the other iterator is set as current.
453     * else i.e. neither of the moveForward is true then
454     * the state is AFTERLAST
455     * return true.
456     * @usage assistance in next method when fetching direction
457     * changes from backward to forward
458     * @param currentIterator current iterator
459     * @param otherIterator other iterator which is not current
460     * @param currentReferences given selected columns of current iterator
461     * @param otherReferences given selected columns of other iterator
462     * @param reverse true if left iterator is current iterator, false when
463     * right iterator is current iterator.
464     * @return FALSE if both underlying iterator has no nore records, true otherwise.
465     * @throws DException
466     */

467    private boolean iteratePositiveAfterNegativeWhenOneIsCurrent(_Iterator currentIterator, _Iterator otherIterator, _Reference[] currentReferences, _Reference[] otherReferences, int reverse) throws DException {
468       boolean currentNext = moveForward(currentIterator, currentIterator.getColumnValues(currentReferences), currentReferences, reverse);
469       boolean otherNext = moveForward(otherIterator, otherIterator.getColumnValues(otherReferences), otherReferences, reverse);
470       if (currentNext && otherNext) {
471          Object JavaDoc currentObject = currentIterator.getColumnValues(currentReferences);
472          Object JavaDoc otherObject = otherIterator.getColumnValues(otherReferences);
473          int cmp = compare(currentObject, otherObject);
474          if (cmp == 0) {
475             state = BOTHHAVESAMEDATA;
476          } else if (cmp > 0) {
477             state = -state;
478             currentIterator.previous();
479          } else {
480             otherIterator.previous();
481          }
482       } else if (currentNext) {
483          otherIterator.last();
484       } else if (otherNext) {
485          currentIterator.last();
486          state = -state;
487       } else {
488          state = AFTERLAST;
489          return false;
490       }
491       return true;
492    }
493
494    /**
495     * This method is responsible to navigate both underlying iterators in forward
496     * direction to next distinct record. Selected column values of next records
497     * are compared. Iterator with smaller values is made as Current Iterator.
498     * If there are no records in current iterator, state is set to ONLYFIRSTHASDATA
499     * or ONLYSECONDHASDATA accordingly. state is set to BOTHHAVESAMEDATA, if
500     * selected column values of next distinct records of both iterators are same.
501     *
502     * DETAILED DOCUMENTAION
503     *
504     * this method is called by next when the state is BOTHHAVESAMEDATA
505     * Algo :::::
506     * calls the moveForward for both the iterators
507     * if the moveForward for both the iterators are true then.
508     * we compare the records pointed to by the iterators
509     * if both are same then
510     * set state = BOTHHAVESAMEDATA
511     * else
512     * the iterator with the smaller value is set as current and the previous of the other iterator is called
513     * else if the current iterator's forward is true then
514     * we call the last of the other iterator
515     * and set the state as SECONDISCURRENT
516     * else if the other itertor's forward is true then
517     * we call the last of the current iterator
518     * and set the state as FIRSTISCURRENT
519     * else i.e. neither of the two is true then
520     * state is set as AFTERLAST
521     * @param currentIterator
522     * @param otherIterator
523     * @param currentReferences
524     * @param otherReferences
525     * @param reverse
526     * @return
527     * @throws DException
528     */

529    private boolean iteratePositiveAfterNegativeWhenBothHaveSameData(_Iterator currentIterator, _Iterator otherIterator, _Reference[] currentReferences, _Reference[] otherReferences, int reverse) throws DException {
530       boolean currentNext = moveForward(currentIterator, currentIterator.getColumnValues(currentReferences), currentReferences, reverse);
531       boolean otherNext = moveForward(otherIterator, otherIterator.getColumnValues(otherReferences), otherReferences, reverse);
532       if (currentNext && otherNext) {
533          Object JavaDoc currentObject = currentIterator.getColumnValues(currentReferences);
534          Object JavaDoc otherObject = otherIterator.getColumnValues(otherReferences);
535          int cmp = compare(currentObject, otherObject);
536          if (cmp == 0) {
537             state = BOTHHAVESAMEDATA;
538          } else if (cmp < 0) {
539             state = SECONDISCURRENT;
540             currentIterator.previous();
541          } else {
542             state = FIRSTISCURRENT;
543             otherIterator.previous();
544          }
545       } else if (currentNext) {
546          otherIterator.last();
547          state = SECONDISCURRENT;
548       } else if (otherNext) {
549          currentIterator.last();
550          state = FIRSTISCURRENT;
551       } else {
552          state = AFTERLAST;
553          return false;
554       }
555       return true;
556    }
557
558    /**
559     * This method moves the iterator to the next distinct record.
560     * it calls next of the current iterator until it finds a distinct record if it cannot it returns false.
561     * @param iterator
562     * @param value the value that is compared to the next records until a different record is found.
563     * @param references
564     * @param reverse 1 means left, -1 means right
565     * @return
566     * @throws DException
567     */

568    private boolean moveForward(_Iterator iterator, Object JavaDoc value, _Reference[] references, int reverse) throws DException {
569       while (iterator.next()) {
570          SuperComparator comparator = reverse == 1 ? leftComparator : rightComparator;
571          if (comparator.compare(iterator.getColumnValues(references), value) != 0) {
572             return true;
573          }
574       }
575       return false;
576    }
577
578    /**
579     * This method is responsible for retriving previous record of Union Iterator.
580     * 1. If the state denotes that one of the iterator is current. Previous
581     * distinct record is retrived from CURRENT iterator. Goto 3.
582     * 2. If the state is BOTHHAVESAMEDATA, previous distinct record is retrived
583     * from both of the underlying iterators. Goto 3
584     * 3. Compare the values of selected columns, Make one of iterator to CURRENT,
585     * which has larger values of selected columns as compared to that of other
586     * iterator) and update the state acc. to new compare result.
587     * 4. If state is ONLYFIRSTHASDATA or ONLYSECONDHASDATA it means only one of
588     * the iterator has data that is navigated in backward direction to retrieve
589     * previous distinct record.
590     *
591     * For backward fetching after forward fetching (if first or next method
592     * has called before call to this previous method),special handing has been done.
593     * Both underlying iterators are navigated in such a way to produce the same
594     * state of both underlying iterators same as before call to forwards fetching
595     * method (first or next method) . In forward fetching records from the
596     * iterator having smaller values of selected columns are returned, if any one
597     * of the iterator has no records, it's first record's values are compared with
598     * that of the selected column values of the another iterator. Smaller Values
599     * must be returned first. Hence, the iterator having larger values is navigated
600     * back to its previous state till distinct selected column values are found.
601     * Thus, maintaining the previous state of both underlying iterators and
602     * returning the appropriate selected columns values.
603     *
604     * DETAILED DOCUMENTATION
605     *
606     * this method aligns the iterator to the previous distinct record.
607     * if the state is :
608     * INVALIDSTATE : throw Exception
609     * BEFOREFIRST : return false
610     * AFTERLAST : call last()
611     * ONLYFIRSTHAVEDATA :
612     * if the direction is FORWARD i.e. it is a case of mixed fetching
613     * then call the iterateNegativeAfterPositiveWhenOneHasData() method
614     * else
615     * change the direction flag to BACKWARD
616     * call the moveBackward() method with the leftIterator
617     * if moveBackward() is false then set state = AFTERLAST.
618     * FIRSTISCURRENT :
619     * if the direction flag = FORWARD i.e. it is case of mixed fetching then
620     * call the iterateNegativeAfterPositiveWhenOneIsCurrent() method
621     * else
622     * call the iterateNegative() method
623     * SECONDISCURRENT :
624     * same as the above case
625     * BOTHHAVESAMEDATA :
626     * if the direction flag = FORWARD
627     * call the iterateNegativeAfterPositiveWhenBothHaveSameData()
628     * else
629     * call the iterateNegativeWhenBoth()
630     *
631     * @return true if either of the iterator has more distinct record in
632     * same backward navigation, false, otherwise.
633     * @throws com.daffodilwoods.database.resource.DException
634     */

635    public boolean previous() throws com.daffodilwoods.database.resource.DException {
636       switch (state) {
637          case INVALIDSTATE:
638             throw new DException("DSE4117", null);
639          case BEFOREFIRST:
640             return false;
641          case AFTERLAST:
642             return last();
643          case ONLYFIRSTHAVEDATA:
644             if (direction == FORWARD) {
645                return iterateNegativeAfterPositiveWhenOneHasData(leftIterator, rightIterator, orderLeftCD, orderRightCD, 1);
646             }
647             direction = BACKWARD;
648             Object JavaDoc val = leftIterator.getColumnValues(orderLeftCD);
649             boolean flag = moveBackward(leftIterator, val, orderLeftCD, 1);
650             state = flag ? state : BEFOREFIRST;
651             return flag;
652          case ONLYSECONDHAVEDATA:
653             if (direction == FORWARD) {
654                return iterateNegativeAfterPositiveWhenOneHasData(rightIterator, leftIterator, orderRightCD, orderLeftCD, -1);
655             }
656             direction = BACKWARD;
657             Object JavaDoc val1 = rightIterator.getColumnValues(orderRightCD);
658             boolean flag1 = moveBackward(rightIterator, val1, orderRightCD, -1);
659             state = flag1 ? state : BEFOREFIRST;
660             return flag1;
661          case FIRSTISCURRENT:
662             if (direction == FORWARD) {
663                return iterateNegativeAfterPositiveWhenOneIsCurrent(leftIterator, rightIterator, orderLeftCD, orderRightCD, 1);
664             }
665             return iterateNegative(leftIterator, rightIterator, 1, orderLeftCD, orderRightCD);
666          case SECONDISCURRENT:
667             if (direction == FORWARD) {
668                return iterateNegativeAfterPositiveWhenOneIsCurrent(rightIterator, leftIterator, orderRightCD, orderLeftCD, -1);
669             }
670             return iterateNegative(rightIterator, leftIterator, -1, orderRightCD, orderLeftCD);
671          case BOTHHAVESAMEDATA:
672             if (direction == FORWARD) {
673                return iterateNegativeAfterPositiveWhenBothHaveSameData(rightIterator, leftIterator, orderRightCD, orderLeftCD, -1);
674             }
675             return iterateNegativeWhenBoth();
676       }
677       return false;
678    }
679
680    /**
681     * This method is responsible to navigate one of the underlying iterator in
682     * backward direction to previous distinct record, when both of the underlying
683     * iterators have data but one of the iterator is current. The purpose of
684     * this method is to navigate current iterator in backward direction to previous
685     * distinct record. If there are no distinct records in current iterator,
686     * state is set to ONLYFIRSTHASDATA or ONLYSECONDHASDATA accordingly.
687     *
688     * DETAILED DOCUMENTAION
689     *
690     * this method is called by the previous() when the state is FIRSTISCURRENT or SECONDISCURRENT and it is not a mixed fetching case
691     * ALGO :::::::::
692     * the direction flag is changed to BACKWARD
693     * we call the moveBackward() for the first iterator this aligns first iterator to the previous distinct record
694     * if the moveBackward() is false
695     * state is set as the other iterator has data i.e either ONLYFIRSTHAVEDATA or ONLYSECONDHAVEDATA according to which is current
696     * else
697     * we compare the records
698     * the state is set accordingly that is the one with the larger value is set as current
699     * if the data are same then the state is set = BOTHHAVESAMEDATA
700     * @throws DException
701     * @usage assistance in previous method
702     * @param firstIterator current iterator
703     * @param secondIterator other iterator which is not current
704     * @param reverse {1 or -1} 1 when left iterator is current, -1 when
705     * right iterator is current.
706     * @param firstReferences given selected columns of current iterator
707     * @param secondReferences given selected columns of other iterator
708     * @return TRUE
709     */

710    private boolean iterateNegative(_Iterator firstIterator, _Iterator secondIterator, int reverse, _Reference[] firstReferences, _Reference[] secondReferences) throws DException {
711       direction = BACKWARD;
712       Object JavaDoc toCompare = firstIterator.getColumnValues(firstReferences);
713       int cmp = -1;
714       boolean flag = moveBackward(firstIterator, toCompare, firstReferences, reverse); // Now firstIterator is at BEFOREFIRST.
715
if (!flag) {
716          state = reverse == 1 ? ONLYSECONDHAVEDATA : ONLYFIRSTHAVEDATA;
717          return true;
718       }
719       Object JavaDoc first = firstIterator.getColumnValues(firstReferences);
720       Object JavaDoc second = secondIterator.getColumnValues(secondReferences);
721       state = reverse == 1 ? getState(compare(second, first)) :getState(compare(first, second));
722
723
724       return true;
725    }
726
727    /**
728     * Both Iterator will move in backward direction and maintain the current status of iterators.
729     */

730
731    /**
732     * This method is responsible to navigate current underlying iterator in
733     * backward direction to distinct record. Selected column values of previous
734     * record of current iterator are compared with that of other iterator. Iterator
735     * with larger values is made as Current Iterator. If there are no records
736     * in current iterator, state is set to ONLYFIRSTHASDATA or ONLYSECONDHASDATA
737     * accordingly.
738     *
739     * DETAILED DOCUMENTAION
740     *
741     * this method is called by the previous() method when the state is BOTHHAVESAMEDATA and it is not a case of mixed fetching
742     * ALGO::::::::::
743     * direction flag is reset to BACKWARD
744     * moveBackward() is called for both iterators
745     * if moveBackward() for the current iterator is true then
746     * if the moveBackward() for the other iterator is true then
747     * compare the values of the iterators
748     * if both are same then
749     * state = BOTHHAVESAMEDATA
750     * else
751     * the iterator with the larger value is set as current
752     * else i.e. the moveBackward() of the other itertor is false
753     * state is set to ONLYFIRSTHAVEDATA
754     * else i.e. the moveBackward() of the current iterator is false
755     * if the moveBackward() of the other iterator is true
756     * state is set ONLYSECONDHAVEDATA
757     * else i.e. neither of the two is true
758     * state is set to BEFOREFIRST
759     *
760     * @return it returns true if the state is not BEFOREFIRST
761     * @throws DException
762     */

763    private boolean iterateNegativeWhenBoth() throws DException {
764       direction = BACKWARD;
765       boolean flag1 = moveBackward(leftIterator, leftIterator.getColumnValues(orderLeftCD), orderLeftCD, 1);
766       boolean flag2 = moveBackward(rightIterator, rightIterator.getColumnValues(orderRightCD), orderRightCD, -1);
767       if (flag1) {
768          if (flag2) {
769             int cmp = compare(leftIterator.getColumnValues(orderLeftCD), rightIterator.getColumnValues(orderRightCD));
770             state = cmp == 0 ? BOTHHAVESAMEDATA : cmp > 0 ? FIRSTISCURRENT : SECONDISCURRENT;
771          } else {
772             state = ONLYFIRSTHAVEDATA;
773          }
774       } else {
775          if (flag2) {
776             state = ONLYSECONDHAVEDATA;
777          } else {
778             state = BEFOREFIRST;
779          }
780       }
781       return state != BEFOREFIRST;
782    }
783
784    /**
785     * This method is called by previous in the case of mixed fetching when
786     * previous method is called after next method and state of iterator corresponds
787     * to case when only one of the iterator has data. Other iterator's selected
788     * column values of last record will be checked with that of previous distinct
789     * record of current iterator. If the other iterator's last record will have
790     * larger values, these values must be retruned first, hence, it is made as
791     * current iterator and current iterator is navigated revert back to next
792     * state, otherwise, state remains to ONEISCURRENT (FIRST or SECOND same as
793     * before) and other iterator is set after last.
794     *
795     * DETAILED DOCUMENTATION
796     *
797     * This method is called by the previous() method when the state is ONLYFIRSTHAVEDATA and it is a case of mixed fetching
798     * ALGO ::::
799     * moveBackward() is called for the current iterator this aligns the current iterator to the previous distinct record
800     * last of the other iterator is called to align it to it's last record
801     * if both moveBackward() and last are true then
802     * compare the two values
803     * if both are same then
804     * set state = BOTHHAVESAMEDATA
805     * else
806     * the iterator with the larger value is set as current
807     * and the other iterator's next is called
808     * else if the other iterator's last is true and moveBackward() of the current iterator is false
809     * current iterator' first() is called and the other iterator is set as current
810     * else i.e. neither is true
811     * then the state is set as BEFOREFIRST
812     * @usage assistance in previous method when fetching direction
813     * changes from forward to backward
814     * @param currentIterator current iterator
815     * @param otherIterator other iterator which is not current
816     * @param currentReferences given selected columns of current iterator
817     * @param otherReferences given selected columns of other iterator
818     * @param reverse true if left iterator is has data, false when
819     * right iterator has data
820     * @return FALSE if current iterator has no more records, true otherwise.
821     * @throws DException
822     */

823    private boolean iterateNegativeAfterPositiveWhenOneHasData(_Iterator currentIterator, _Iterator otherIterator, _Reference[] currentReferences, _Reference[] otherReferences, int reverse) throws DException {
824       boolean currentPrevious = moveBackward(currentIterator, currentIterator.getColumnValues(currentReferences), currentReferences, reverse);
825       boolean otherLast = otherIterator.last();
826       if (currentPrevious && otherLast) {
827          Object JavaDoc currentObject = currentIterator.getColumnValues(currentReferences);
828          Object JavaDoc otherObject = otherIterator.getColumnValues(otherReferences);
829          int cmp = compare(currentObject, otherObject);
830          if (cmp == 0) {
831             state = BOTHHAVESAMEDATA;
832          } else if (cmp < 0) {
833             state = state == ONLYSECONDHAVEDATA ? FIRSTISCURRENT
834                 : state == ONLYFIRSTHAVEDATA ? SECONDISCURRENT : state;
835             currentIterator.next();
836          } else {
837             otherIterator.next();
838          }
839       } else if (currentPrevious) {
840       } else if (otherLast) {
841          currentIterator.first();
842          state = state == ONLYSECONDHAVEDATA ? FIRSTISCURRENT
843              : state == ONLYFIRSTHAVEDATA ? SECONDISCURRENT : state;
844       } else {
845          state = BEFOREFIRST;
846          return false;
847       }
848       return true;
849    }
850
851    /**
852     * This method is called by previous when the state is FIRSTISCURRENT and
853     * previously fetching direction was forward (first or next called).
854     * Previous distinct record is retrieved from both of the underlying iterator.
855     * If both values are same, state is set to BOTHHAVESAMEDATA. Otherwise,
856     * The next of underlying iterator is called which has smaller values of
857     * selected columns, since smaller values will be returned in the next call
858     * of previous method.
859     *
860     * DETAILED DOCUMENTATION
861     *
862     * This method is called by previous() when the state is FIRSTISCURRENT or SECONDISCURRENT and it is a case of mixed fetching
863     * ALGO ::::
864     * moveBackward() is called for the current iterator and the other iterator
865     * if both the moveBackward() are true then
866     * the two values are compared
867     * if the two values are same then
868     * state is set equal to BOTHHAVESAMEDATA
869     * else
870     * the iterator with the larger value is set as current and the next of the other iterator is called.
871     * else if only the moveBackward() of the current iterator is true then
872     * we call the other iterator's first()
873     * else if only the moveBackward() of the other iterator is true then
874     * we call the current iterator's first() and the other iterator is set as current
875     * else i.e. neither of the two are true then
876     * the state is set as BEFOREFIRST
877
878     * @usage assistance in previous method when fetching direction
879     * changes from forward to backward
880     * @param currentIterator current iterator
881     * @param otherIterator other iterator which is not current
882     * @param currentReferences given selected columns of current iterator
883     * @param otherReferences given selected columns of other iterator
884     * @param reverse true if left iterator is current iterator, false when
885     * right iterator is current iterator.
886     * @return FALSE if both underlying iterator has no nore records, true otherwise.
887     */

888    private boolean iterateNegativeAfterPositiveWhenOneIsCurrent(_Iterator currentIterator, _Iterator otherIterator, _Reference[] currentReferences, _Reference[] otherReferences, int reverse) throws DException {
889       boolean currentPrevious = moveBackward(currentIterator, currentIterator.getColumnValues(currentReferences), currentReferences, reverse);
890       boolean otherPrevious = moveBackward(otherIterator, otherIterator.getColumnValues(otherReferences), otherReferences, reverse);
891       if (currentPrevious && otherPrevious) {
892          Object JavaDoc currentObject = currentIterator.getColumnValues(currentReferences);
893          Object JavaDoc otherObject = otherIterator.getColumnValues(otherReferences);
894          int cmp = compare(currentObject, otherObject);
895          if (cmp == 0) {
896             state = BOTHHAVESAMEDATA;
897          } else if (cmp < 0) {
898             state = -state;
899             currentIterator.next();
900          } else {
901             otherIterator.next();
902          }
903       } else if (currentPrevious) {
904          otherIterator.first();
905       } else if (otherPrevious) {
906          currentIterator.first();
907          state = -state;
908       } else {
909          state = BEFOREFIRST;
910          return false;
911       }
912       return true;
913    }
914
915    /**
916     * This method is responsible to navigate both underlying iterators in backward
917     * direction to previous distinct record. Selected column values of previous
918     * records from both iterators are compared. Iterator with larger values is
919     * made as Current Iterator. If there are no records in current iterator,
920     * state is set to ONLYFIRSTHASDATA or ONLYSECONDHASDATA accordingly. state
921     * is set to BOTHHAVESAMEDATA, if selected column values of previous distinct
922     * records of both iterators are same.
923     *
924     * DETAILED DOCUMENTAION
925     *
926     * this method is called by the previous() method when the state is BOTHHAVESAMEDATA and it is a case of mixed fetching
927     * ALGO::::::::
928     * moveBackward() is called for both the iterators
929     * if both moveBackward() return true then
930     * we compare the values of the iterators
931     * if both have same data then
932     * state is set = BOTHHAVESAMEDATA
933     * else
934     * the iterator with the larger value is set as current and the next of the other iterator is called
935     * if only the moveBackward() of the current iterator is true then
936     * we call the other iterator's first
937     * and the state is set as FIRSTISCURRENT
938     * else if only the moveBackward() of the other iterator is true
939     * current iterator's first is called and the other iterator is set as current
940     * else i.e. neither of the two is true
941     * the state is set to BEFOREFIRST
942     * false is returned
943     * @param currentIterator
944     * @param otherIterator
945     * @param currentReferences
946     * @param otherReferences
947     * @param reverse
948     * @return
949     * @throws DException
950     */

951    private boolean iterateNegativeAfterPositiveWhenBothHaveSameData(_Iterator currentIterator, _Iterator otherIterator, _Reference[] currentReferences, _Reference[] otherReferences, int reverse) throws DException {
952       boolean currentPrevious = moveBackward(currentIterator, currentIterator.getColumnValues(currentReferences), currentReferences, reverse);
953       boolean otherPrevious = moveBackward(otherIterator, otherIterator.getColumnValues(otherReferences), otherReferences, reverse);
954       if (currentPrevious && otherPrevious) {
955          Object JavaDoc currentObject = currentIterator.getColumnValues(currentReferences);
956          Object JavaDoc otherObject = otherIterator.getColumnValues(otherReferences);
957          int cmp = compare(currentObject, otherObject);
958          if (cmp == 0) {
959             state = BOTHHAVESAMEDATA;
960          } else if (cmp < 0) {
961             state = SECONDISCURRENT;
962             currentIterator.next();
963          } else {
964             state = FIRSTISCURRENT;
965             otherIterator.next();
966          }
967       } else if (currentPrevious) {
968          otherIterator.first();
969          state = FIRSTISCURRENT;
970       } else if (otherPrevious) {
971          currentIterator.first();
972          state = SECONDISCURRENT;
973       } else {
974          state = BEFOREFIRST;
975          return false;
976       }
977       return true;
978    }
979
980    /**
981     * Move the single iterator on just previous distinct record.
982     */

983
984    /**
985     * this method is called by the previous() method
986     * this method aligns the iterator to the previous disticnt record
987     * ALGO:::::
988     * it calls the previous of the iterator until a different record is found
989     * @param iterator
990     * @param value
991     * @param references
992     * @param reverse
993     * @return
994     * @throws DException
995     */

996    private boolean moveBackward(_Iterator iterator, Object JavaDoc value, _Reference[] references, int reverse) throws DException {
997       while (iterator.previous()) {
998          SuperComparator comparator = reverse == 1 ? leftComparator : rightComparator;
999          if (comparator.compare(iterator.getColumnValues(references), value) != 0) {
1000            return true;
1001         }
1002      }
1003      return false;
1004   }
1005
1006   /**
1007    * This method is used to get the lowest level iterator.
1008    * @param column column corresponding to which iterator is to return.
1009    * @return same iterator.
1010    * @throws DException
1011    */

1012   public _Iterator getBaseIterator(ColumnDetails column) throws com.daffodilwoods.database.resource.DException {
1013      return this;
1014   }
1015
1016   /**
1017    * This method is responsible to display the executionPlan of a Select Query.
1018    * @return _ExecutionPlan
1019    * @throws DException
1020    */

1021   public _ExecutionPlan getExecutionPlan() throws DException {
1022      _ExecutionPlan cplans[] = new _ExecutionPlan[2];
1023      cplans[0] = leftIterator.getExecutionPlan();
1024      cplans[1] = rightIterator.getExecutionPlan();
1025      return new ExecutionPlan("UnionDistinctIterator", cplans, null, null, null);
1026   }
1027
1028   /**
1029    * This method is responsible to display the iterators hierarchy of a Select Query.
1030    * @return ExecutionPlanForBrowser
1031    * @throws DException
1032    */

1033   public ExecutionPlanForBrowser getExecutionPlanForBrowser() throws DException {
1034      ExecutionPlanForBrowser cplans[] = new ExecutionPlanForBrowser[2];
1035      cplans[0] = leftIterator.getExecutionPlanForBrowser();
1036      cplans[1] = rightIterator.getExecutionPlanForBrowser();
1037      return new ExecutionPlanForBrowser("Union Distinct", "Union Distinct Iterator", cplans, null, null, null);
1038   }
1039
1040    public String JavaDoc toString() {
1041      return "UnionDistinctIterator [" + leftIterator + "] [" + rightIterator + "] ";
1042   }
1043
1044
1045   private int getState(int compareResult){
1046      return stateToSet[compareResult + 2 ];
1047   }
1048
1049}
1050
Popular Tags