KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2
3    Derby - Class org.apache.derby.impl.sql.execute.SetOpResultSet
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.error.StandardException;
25
26 import org.apache.derby.iapi.services.loader.GeneratedMethod;
27 import org.apache.derby.iapi.services.sanity.SanityManager;
28
29 import org.apache.derby.iapi.sql.Activation;
30 import org.apache.derby.iapi.sql.ResultDescription;
31
32 import org.apache.derby.iapi.sql.execute.CursorResultSet;
33 import org.apache.derby.iapi.sql.execute.ExecPreparedStatement;
34 import org.apache.derby.iapi.sql.execute.ExecRow;
35 import org.apache.derby.iapi.sql.execute.NoPutResultSet;
36
37 import org.apache.derby.iapi.types.DataValueDescriptor;
38 import org.apache.derby.iapi.types.Orderable;
39 import org.apache.derby.iapi.types.RowLocation;
40
41 import org.apache.derby.impl.sql.compile.IntersectOrExceptNode;
42
43 /**
44  * Takes the result set produced by an ordered UNION ALL of two tagged result sets and produces
45  * the INTERSECT or EXCEPT of the two input result sets. This also projects out the tag, the last column
46  * of the input rows.
47  */

48 class SetOpResultSet extends NoPutResultSetImpl
49     implements CursorResultSet
50 {
51     private final NoPutResultSet leftSource;
52     private final NoPutResultSet rightSource;
53     private final Activation activation;
54     private final int opType;
55     private final boolean all;
56     private final int resultSetNumber;
57     private DataValueDescriptor[] prevCols; /* Used to remove duplicates in the EXCEPT DISTINCT case.
58                                              * It is equal to the previously output columns.
59                                              */

60     private int rightDuplicateCount; // Number of duplicates of the current row from the right input
61
private ExecRow leftInputRow;
62     private ExecRow rightInputRow;
63
64     private final int[] intermediateOrderByColumns;
65     private final int[] intermediateOrderByDirection;
66
67     /* Run time statistics variables */
68     private int rowsSeenLeft;
69     private int rowsSeenRight;
70     private int rowsReturned;
71
72     SetOpResultSet( NoPutResultSet leftSource,
73                     NoPutResultSet rightSource,
74                     Activation activation,
75                     int resultSetNumber,
76                     long optimizerEstimatedRowCount,
77                     double optimizerEstimatedCost,
78                     int opType,
79                     boolean all,
80                     int intermediateOrderByColumnsSavedObject,
81                     int intermediateOrderByDirectionSavedObject)
82     {
83         super(activation, resultSetNumber,
84               optimizerEstimatedRowCount, optimizerEstimatedCost);
85         this.leftSource = leftSource;
86         this.rightSource = rightSource;
87         this.activation = activation;
88         this.resultSetNumber = resultSetNumber;
89         this.opType = opType;
90         this.all = all;
91
92         ExecPreparedStatement eps = activation.getPreparedStatement();
93         intermediateOrderByColumns = (int[]) eps.getSavedObject(intermediateOrderByColumnsSavedObject);
94         intermediateOrderByDirection = (int[]) eps.getSavedObject(intermediateOrderByDirectionSavedObject);
95         constructorTime += getElapsedMillis(beginTime);
96     }
97
98     /**
99      * open the first source.
100      * @exception StandardException thrown on failure
101      */

102     public void openCore() throws StandardException
103     {
104         beginTime = getCurrentTimeMillis();
105         if (SanityManager.DEBUG)
106             SanityManager.ASSERT( ! isOpen, "SetOpResultSet already open");
107
108         isOpen = true;
109         leftSource.openCore();
110         rightSource.openCore();
111         rightInputRow = rightSource.getNextRowCore();
112         if (rightInputRow != null)
113         {
114             rowsSeenRight++;
115         }
116
117         numOpens++;
118
119         openTime += getElapsedMillis(beginTime);
120     } // end of openCore
121

122     /**
123      * @return the next row of the intersect or except, null if there is none
124      * @exception StandardException thrown on failure
125      */

126     public ExecRow getNextRowCore() throws StandardException
127     {
128         beginTime = getCurrentTimeMillis();
129         if ( isOpen )
130         {
131             while( (leftInputRow = leftSource.getNextRowCore()) != null)
132             {
133                 rowsSeenLeft++;
134
135                 DataValueDescriptor[] leftColumns = leftInputRow.getRowArray();
136                 if( !all)
137                 {
138                     if( isDuplicate( leftColumns))
139                         continue; // Get the next left row
140
prevCols = leftInputRow.getRowArrayClone();
141                 }
142                 int compare = 0;
143                 // Advance the right until there are no more right rows or leftRow <= rightRow
144
while ( rightInputRow != null && (compare = compare(leftColumns, rightInputRow.getRowArray())) > 0)
145                 {
146                     rightInputRow = rightSource.getNextRowCore();
147                     if (rightInputRow != null)
148                     {
149                         rowsSeenRight++;
150                     }
151                 }
152
153                 if( rightInputRow == null || compare < 0)
154                 {
155                     // The left row is not in the right source.
156
if( opType == IntersectOrExceptNode.EXCEPT_OP)
157                         // Output this row
158
break;
159                 }
160                 else
161                 {
162                     // The left and right rows are the same
163
if( SanityManager.DEBUG)
164                         SanityManager.ASSERT( rightInputRow != null && compare == 0,
165                                               "Intersect/Except execution has gotten confused.");
166                     if ( all)
167                     {
168                         // Just advance the right input by one row.
169
rightInputRow = rightSource.getNextRowCore();
170                         if (rightInputRow != null)
171                         {
172                             rowsSeenRight++;
173                         }
174                     }
175
176                     // If !all then we will skip past duplicates on the left at the top of this loop,
177
// which will then force us to skip past any right duplicates.
178
if( opType == IntersectOrExceptNode.INTERSECT_OP)
179                         break; // output this row
180

181                     // opType == IntersectOrExceptNode.EXCEPT_OP
182
// This row should not be ouput
183
}
184             }
185         }
186         currentRow = leftInputRow;
187         setCurrentRow( currentRow );
188
189         if (currentRow != null) {
190            rowsReturned++;
191         }
192
193         nextTime += getElapsedMillis(beginTime);
194         return currentRow;
195     } // end of getNextRowCore
196

197     private void advanceRightPastDuplicates( DataValueDescriptor[] leftColumns)
198         throws StandardException
199     {
200         while ((rightInputRow = rightSource.getNextRowCore()) != null)
201         {
202             rowsSeenRight++;
203
204             if (compare(leftColumns, rightInputRow.getRowArray()) == 0)
205                 continue;
206         }
207     } // end of advanceRightPastDuplicates
208

209     private int compare( DataValueDescriptor[] leftCols, DataValueDescriptor[] rightCols)
210         throws StandardException
211     {
212         for( int i = 0; i < intermediateOrderByColumns.length; i++)
213         {
214             int colIdx = intermediateOrderByColumns[i];
215             if( leftCols[colIdx].compare( Orderable.ORDER_OP_LESSTHAN,
216                                           rightCols[colIdx],
217                                           true, // nulls sort high
218
false))
219                 return -1 * intermediateOrderByDirection[i];
220             if( ! leftCols[colIdx].compare( Orderable.ORDER_OP_EQUALS,
221                                             rightCols[colIdx],
222                                             true, // nulls sort high
223
false))
224                 return intermediateOrderByDirection[i];
225         }
226         return 0;
227     } // end of compare
228

229     private boolean isDuplicate( DataValueDescriptor[] curColumns)
230         throws StandardException
231     {
232         if( prevCols == null)
233             return false;
234         /* Note that intermediateOrderByColumns.length can be less than prevCols.length if we know that a
235          * subset of the columns is a unique key. In that case we only need to look at the unique key.
236          */

237         for( int i = 0; i < intermediateOrderByColumns.length; i++)
238         {
239             int colIdx = intermediateOrderByColumns[i];
240             if( ! curColumns[colIdx].compare( Orderable.ORDER_OP_EQUALS, prevCols[colIdx], true, false))
241                 return false;
242         }
243         return true;
244     }
245
246     public ExecRow getCurrentRow()
247     {
248         return currentRow;
249     }
250     
251     /**
252      * If the result set has been opened,
253      * close the currently open source.
254      *
255      * @exception StandardException thrown on error
256      */

257     public void close() throws StandardException
258     {
259         beginTime = getCurrentTimeMillis();
260         if ( isOpen )
261         {
262             clearCurrentRow();
263             prevCols = null;
264             leftSource.close();
265             rightSource.close();
266             super.close();
267         }
268         else
269             if (SanityManager.DEBUG)
270                 SanityManager.DEBUG("CloseRepeatInfo","Close of SetOpResultSet repeated");
271
272         closeTime += getElapsedMillis(beginTime);
273     } // end of close
274

275     public void finish() throws StandardException
276     {
277         leftSource.finish();
278         rightSource.finish();
279         finishAndRTS();
280     }
281
282     /**
283      * Return the total amount of time spent in this ResultSet
284      *
285      * @param type CURRENT_RESULTSET_ONLY - time spent only in this ResultSet
286      * ENTIRE_RESULTSET_TREE - time spent in this ResultSet and below.
287      *
288      * @return long The total amount of time spent (in milliseconds).
289      */

290     public long getTimeSpent(int type)
291     {
292         long totTime = constructorTime + openTime + nextTime + closeTime;
293
294         if (type == NoPutResultSet.CURRENT_RESULTSET_ONLY)
295         {
296             return totTime - leftSource.getTimeSpent(ENTIRE_RESULTSET_TREE)
297               - rightSource.getTimeSpent(ENTIRE_RESULTSET_TREE);
298         }
299         else
300         {
301             return totTime;
302         }
303     } // end of getTimeSpent
304

305     /**
306      * @see CursorResultSet
307      *
308      * @return the row location of the current cursor row.
309      * @exception StandardException thrown on failure
310      */

311     public RowLocation getRowLocation() throws StandardException
312     {
313         // RESOLVE: What is the row location of an INTERSECT supposed to be: the location from the
314
// left side, the right side, or null?
315
return ((CursorResultSet)leftSource).getRowLocation();
316     }
317
318     /**
319      * Return the set operation of this <code>SetOpResultSet</code>
320      *
321      * @return the set operation of this ResultSet, the value is either
322      * <code>IntersectOrExceptNode.INTERSECT_OP</code> for
323      * Intersect operation or <code>IntersectOrExceptNode.EXCEPT_OP
324      * </code> for Except operation
325      *
326      * @see org.apache.derby.impl.sql.compile.IntersectOrExceptNode
327      */

328     public int getOpType()
329     {
330         return opType;
331     }
332
333     /**
334      * Return the result set number
335      *
336      * @return the result set number
337      */

338     public int getResultSetNumber()
339     {
340         return resultSetNumber;
341     }
342
343     /**
344      * Return the left source input of this <code>SetOpResultSet</code>
345      *
346      * @return the left source input of this <code>SetOpResultSet</code>
347      * @see org.apache.derby.iapi.sql.execute.NoPutResultSet
348      */

349     public NoPutResultSet getLeftSourceInput()
350     {
351         return leftSource;
352     }
353
354     /**
355      * Return the right source input of this <code>SetOpResultSet</code>
356      *
357      * @return the right source input of this <code>SetOpResultSet</code>
358      * @see org.apache.derby.iapi.sql.execute.NoPutResultSet
359      */

360     public NoPutResultSet getRightSourceInput()
361     {
362         return rightSource;
363     }
364
365     /**
366      * Return the number of rows seen on the left source input
367      *
368      * @return the number of rows seen on the left source input
369      */

370     public int getRowsSeenLeft()
371     {
372         return rowsSeenLeft;
373     }
374
375     /**
376      * Return the number of rows seen on the right source input
377      *
378      * @return the number of rows seen on the right source input
379      */

380     public int getRowsSeenRight()
381     {
382         return rowsSeenRight;
383     }
384
385     /**
386      * Return the number of rows returned from the result set
387      *
388      * @return the number of rows returned from the result set
389      */

390     public int getRowsReturned()
391     {
392         return rowsReturned;
393     }
394 }
395
Popular Tags