KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > derby > impl > sql > execute > DistinctScalarAggregateResultSet


1 /*
2
3    Derby - Class org.apache.derby.impl.sql.execute.DistinctScalarAggregateResultSet
4
5    Licensed to the Apache Software Foundation (ASF) under one or more
6    contributor license agreements. See the NOTICE file distributed with
7    this work for additional information regarding copyright ownership.
8    The ASF licenses this file to you under the Apache License, Version 2.0
9    (the "License"); you may not use this file except in compliance with
10    the License. You may obtain a copy of the License at
11
12       http://www.apache.org/licenses/LICENSE-2.0
13
14    Unless required by applicable law or agreed to in writing, software
15    distributed under the License is distributed on an "AS IS" BASIS,
16    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17    See the License for the specific language governing permissions and
18    limitations under the License.
19
20  */

21
22 package org.apache.derby.impl.sql.execute;
23
24 import org.apache.derby.iapi.services.sanity.SanityManager;
25
26 import org.apache.derby.iapi.sql.execute.ExecRow;
27 import org.apache.derby.iapi.sql.execute.ExecIndexRow;
28 import org.apache.derby.iapi.sql.execute.NoPutResultSet;
29
30 import org.apache.derby.iapi.sql.Activation;
31
32 import org.apache.derby.iapi.store.access.ColumnOrdering;
33 import org.apache.derby.iapi.store.access.SortObserver;
34 import org.apache.derby.iapi.store.access.TransactionController;
35 import org.apache.derby.iapi.store.access.SortController;
36 import org.apache.derby.iapi.store.access.ScanController;
37
38 import org.apache.derby.iapi.services.loader.GeneratedMethod;
39
40
41 import org.apache.derby.iapi.error.StandardException;
42
43 import org.apache.derby.iapi.services.io.FormatableArrayHolder;
44
45 import java.util.Properties JavaDoc;
46
47
48 /**
49  * This ResultSet evaluates scalar aggregates where
50  * 1 (or more, in the future) of the aggregates are distinct.
51  * It will scan the entire source result set and calculate
52  * the scalar aggregates when scanning the source during the
53  * first call to next().
54  *
55  * @author jerry (broken out from SortResultSet)
56  */

57 class DistinctScalarAggregateResultSet extends ScalarAggregateResultSet
58 {
59     private ColumnOrdering[] order;
60     private int maxRowSize;
61     private boolean dropDistinctAggSort;
62     private long sortId;
63
64     // set in open and not modified thereafter
65
private ScanController scanController;
66
67     private ExecIndexRow sortResultRow;
68
69     // remember whether or not any sort was performed
70
private boolean sorted;
71
72     /**
73      * Constructor
74      *
75      * @param s input result set
76      * @param isInSortedOrder true if the source results are in sorted order
77      * @param aggregateItem indicates the number of the
78      * SavedObject off of the PreparedStatement that holds the
79      * AggregatorInfoList used by this routine.
80      * @param a activation
81      * @param ra generated method to build an empty
82      * output row
83      * @param resultSetNumber The resultSetNumber for this result set
84      *
85      * @exception StandardException Thrown on error
86      */

87     DistinctScalarAggregateResultSet(NoPutResultSet s,
88                     boolean isInSortedOrder,
89                     int aggregateItem,
90                     int orderingItem,
91                     Activation a,
92                     GeneratedMethod ra,
93                     int maxRowSize,
94                     int resultSetNumber,
95                     boolean singleInputRow,
96                     double optimizerEstimatedRowCount,
97                     double optimizerEstimatedCost) throws StandardException
98     {
99         super(s, isInSortedOrder, aggregateItem, a, ra,
100               resultSetNumber,
101               singleInputRow,
102               optimizerEstimatedRowCount,
103               optimizerEstimatedCost);
104
105         order = (ColumnOrdering[])
106                     ((FormatableArrayHolder)
107                         (a.getPreparedStatement().getSavedObject(orderingItem)))
108                     .getArray(ColumnOrdering.class);
109
110         this.maxRowSize = maxRowSize;
111
112         constructorTime += getElapsedMillis(beginTime);
113     }
114
115
116     ///////////////////////////////////////////////////////////////////////////////
117
//
118
// ResultSet interface (leftover from NoPutResultSet)
119
//
120
///////////////////////////////////////////////////////////////////////////////
121

122     /**
123      * Open the scan. Load the sorter and prepare to get
124      * rows from it.
125      *
126      * @exception StandardException thrown if cursor finished.
127      */

128     public void openCore() throws StandardException
129     {
130         beginTime = getCurrentTimeMillis();
131         // REVISIT: through the direct DB API, this needs to be an
132
// error, not an ASSERT; users can open twice. Only through JDBC
133
// is access to open controlled and ensured valid.
134
if (SanityManager.DEBUG)
135             SanityManager.ASSERT( ! isOpen, "DistinctScalarResultSet already open");
136
137         sortResultRow = getExecutionFactory().getIndexableRow(sortTemplateRow.getClone());
138         sourceExecIndexRow = getExecutionFactory().getIndexableRow(sortTemplateRow.getClone());
139
140         source.openCore();
141
142         /*
143         ** Load up the sorter because we have something to sort.
144         */

145         scanController = loadSorter();
146         sorted = true;
147
148         isOpen = true;
149         numOpens++;
150
151         openTime += getElapsedMillis(beginTime);
152     }
153
154     /* RESOLVE - THIS NEXT METHOD IS ONLY INCLUDED BECAUSE OF A JIT ERROR. THERE IS NO OTHER
155      * REASON TO OVERRIDE IT IN DistinctScalarAggregateResultSet. THE BUG WAS FOUND IN
156      * 1.1.6 WITH THE JIT.
157      */

158     /**
159      * Return the next row. If it is a scalar aggregate scan
160      *
161      * @exception StandardException thrown on failure.
162      * @exception StandardException ResultSetNotOpen thrown if not yet open.
163      *
164      * @return the next row in the result
165      */

166     public ExecRow getNextRowCore() throws StandardException
167     {
168         ExecIndexRow sortResult = null;
169         ExecRow result = null;
170         ExecIndexRow execIndexRow = null;
171         ExecIndexRow aggResult = null;
172         boolean cloneArg = true;
173
174         beginTime = getCurrentTimeMillis();
175         if (isOpen)
176         {
177             /*
178             ** We are dealing with a scalar aggregate.
179             ** Zip through each row and accumulate.
180             ** Accumulate into the first row. Only
181             ** the first row is cloned.
182             */

183             while ((execIndexRow = getRowFromResultSet(cloneArg)) != null)
184             {
185                 /*
186                 ** Use a clone of the first row as our result.
187                 ** We need to get a clone since we will be reusing
188                 ** the original as the wrapper of the source row.
189                 ** Turn cloning off since we wont be keeping any
190                 ** other rows.
191                 */

192                 if (aggResult == null)
193                 {
194                     cloneArg = false;
195                     aggResult = (ExecIndexRow) execIndexRow.getClone();
196                 }
197                 else
198                 {
199                     /*
200                     ** Accumulate all aggregates. For the distinct
201                     ** aggregates, we'll be accumulating, for the nondistinct
202                     ** we'll be merging.
203                     */

204                     accumulateScalarAggregation(execIndexRow, aggResult, true);
205                 }
206             }
207
208             /*
209             ** If we have aggregates, we need to generate a
210             ** value for them now. Only finish the aggregation
211             ** if we haven't yet (i.e. if countOfRows == 0).
212             ** If there weren't any input rows, we'll allocate
213             ** one here.
214             */

215             if (countOfRows == 0)
216             {
217                 aggResult = finishAggregation(aggResult);
218                 currentRow = aggResult;
219                 setCurrentRow(aggResult);
220                 countOfRows++;
221             }
222         }
223
224         nextTime += getElapsedMillis(beginTime);
225         return aggResult;
226     }
227
228     /**
229      * reopen a scan on the table. scan parameters are evaluated
230      * at each open, so there is probably some way of altering
231      * their values...
232      *
233      * @exception StandardException thrown if cursor finished.
234      */

235     public void reopenCore() throws StandardException
236     {
237         beginTime = getCurrentTimeMillis();
238         if (SanityManager.DEBUG)
239             SanityManager.ASSERT(isOpen, "NormalizeResultSet already open");
240
241         if (scanController != null)
242         {
243             scanController.close();
244             scanController = null;
245         }
246
247         source.reopenCore();
248
249         /*
250         ** Load up the sorter because we have something to sort.
251         */

252         scanController = loadSorter();
253         sorted = true;
254         numOpens++;
255         countOfRows = 0;
256
257         openTime += getElapsedMillis(beginTime);
258     }
259
260         /**
261          * If the result set has been opened,
262          * close the open scan.
263          */

264         public void close() throws StandardException
265         {
266             super.close();
267             closeSource();
268         }
269     ///////////////////////////////////////////////////////////////////////////////
270
//
271
// SCAN ABSTRACTION UTILITIES
272
//
273
///////////////////////////////////////////////////////////////////////////////
274

275     /**
276      * Get a row from the sorter. Side effects:
277      * sets currentRow.
278      *
279      * @exception StandardException Thrown on error
280      */

281     public ExecIndexRow getRowFromResultSet(boolean doClone)
282         throws StandardException
283     {
284         ExecIndexRow inputRow = null;
285         
286         if (scanController.next())
287         {
288             // REMIND: HACKALERT we are assuming that result will
289
// point to what sortResult is manipulating when
290
// we complete the fetch.
291
currentRow = doClone ?
292                 sortResultRow.getClone() : sortResultRow;
293
294             inputRow = getExecutionFactory().getIndexableRow(currentRow);
295
296             scanController.fetch(inputRow.getRowArray());
297         }
298         return inputRow;
299     }
300
301     /**
302      * Close the source of whatever we have been scanning.
303      *
304      * @exception StandardException thrown on error
305      */

306     protected void closeSource() throws StandardException
307     {
308         if (scanController != null)
309         {
310             if (dropDistinctAggSort)
311             {
312                 try
313                 {
314                     getTransactionController().dropSort(sortId);
315                 }
316                 catch (StandardException se)
317                 {
318                     // Eat all errors at close() time
319
}
320                 dropDistinctAggSort = false;
321             }
322             scanController.close();
323             scanController = null;
324         }
325         source.close();
326     }
327
328     ///////////////////////////////////////////////////////////////////////////////
329
//
330
// MISC UTILITIES
331
//
332
///////////////////////////////////////////////////////////////////////////////
333

334     /**
335      * Load up the sorter. Feed it every row from the
336      * source scan. If we have a vector aggregate, initialize
337      * the aggregator for each source row. When done, close
338      * the source scan and open the sort. Return the sort
339      * scan controller.
340      *
341      * @exception StandardException thrown on failure.
342      *
343      * @return the sort controller
344      */

345     private ScanController loadSorter()
346         throws StandardException
347     {
348         SortController sorter;
349         ExecRow sourceRow;
350         int inputRowCountEstimate = (int) optimizerEstimatedRowCount;
351
352         TransactionController tc = getTransactionController();
353
354         /*
355         ** We have a distinct aggregate so, we'll need
356         ** to do a sort. We use all of the sorting columns and
357         ** drop the aggregation on the distinct column. Then
358         ** we'll feed this into the sorter again w/o the distinct
359         ** column in the ordering list.
360         */

361         GenericAggregator[] aggsNoDistinct = getSortAggregators(aggInfoList, true,
362                 activation.getLanguageConnectionContext(), source);
363         SortObserver sortObserver = new AggregateSortObserver(true, aggsNoDistinct, aggregates,
364                                                               sortTemplateRow);
365
366         sortId = tc.createSort((Properties JavaDoc)null,
367                     sortTemplateRow.getRowArray(),
368                     order,
369                     sortObserver,
370                     false, // not in order
371
inputRowCountEstimate, // est rows, -1 means no idea
372
maxRowSize // est rowsize
373
);
374         sorter = tc.openSort(sortId);
375         dropDistinctAggSort = true;
376                 
377         while ((sourceRow = source.getNextRowCore())!=null)
378         {
379             sorter.insert(sourceRow.getRowArray());
380             rowsInput++;
381         }
382
383         /*
384         ** End the sort and open up the result set
385         */

386         sorter.close();
387
388         scanController =
389             tc.openSortScan(sortId, activation.getResultSetHoldability());
390             
391         /*
392         ** Aggs are initialized and input rows
393         ** are in order.
394         */

395         inputRowCountEstimate = rowsInput;
396     
397         return scanController;
398     }
399
400 }
401
Popular Tags