KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2
3    Derby - Class org.apache.derby.impl.sql.execute.OnceResultSet
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.monitor.Monitor;
25
26 import org.apache.derby.iapi.services.sanity.SanityManager;
27
28 import org.apache.derby.iapi.services.stream.HeaderPrintWriter;
29 import org.apache.derby.iapi.services.stream.InfoStreams;
30
31 import org.apache.derby.iapi.sql.conn.StatementContext;
32
33 import org.apache.derby.iapi.sql.execute.ExecRow;
34 import org.apache.derby.iapi.sql.execute.NoPutResultSet;
35
36 import org.apache.derby.iapi.types.DataValueDescriptor;
37 import org.apache.derby.iapi.sql.Activation;
38 import org.apache.derby.iapi.sql.ResultSet;
39
40 import org.apache.derby.iapi.services.loader.GeneratedMethod;
41
42 import org.apache.derby.iapi.reference.SQLState;
43 import org.apache.derby.iapi.error.StandardException;
44
45 /**
46  * Takes an expression subquery's result set and verifies that only
47  * a single scalar value is being returned.
48  * NOTE: A row with a single column containing null will be returned from
49  * getNextRow() if the underlying subquery ResultSet is empty.
50  *
51  * @author jerry
52  */

53 public class OnceResultSet extends NoPutResultSetImpl
54 {
55     /* Statics for cardinality check */
56     public static final int DO_CARDINALITY_CHECK = 1;
57     public static final int NO_CARDINALITY_CHECK = 2;
58     public static final int UNIQUE_CARDINALITY_CHECK = 3;
59
60     /* Used to cache row with nulls for case when subquery result set
61      * is empty.
62      */

63     private ExecRow rowWithNulls;
64
65     /* Used to cache the StatementContext */
66     private StatementContext statementContext;
67
68     // set in constructor and not altered during
69
// life of object.
70
public NoPutResultSet source;
71     private GeneratedMethod emptyRowFun;
72     private int cardinalityCheck;
73     public int subqueryNumber;
74     public int pointOfAttachment;
75
76     //
77
// class interface
78
//
79
public OnceResultSet(NoPutResultSet s, Activation a, GeneratedMethod emptyRowFun,
80                          int cardinalityCheck, int resultSetNumber,
81                          int subqueryNumber, int pointOfAttachment,
82                          double optimizerEstimatedRowCount,
83                          double optimizerEstimatedCost)
84     {
85         super(a, resultSetNumber, optimizerEstimatedRowCount, optimizerEstimatedCost);
86         source = s;
87         this.emptyRowFun = emptyRowFun;
88         this.cardinalityCheck = cardinalityCheck;
89         this.subqueryNumber = subqueryNumber;
90         this.pointOfAttachment = pointOfAttachment;
91         constructorTime += getElapsedMillis(beginTime);
92     }
93
94     //
95
// ResultSet interface (leftover from NoPutResultSet)
96
//
97

98     /**
99      * open a scan on the table. scan parameters are evaluated
100      * at each open, so there is probably some way of altering
101      * their values...
102      *
103      * @exception StandardException thrown if cursor finished.
104      */

105     public void openCore() throws StandardException
106     {
107         /* NOTE: We can't get code generation
108          * to generate calls to reopenCore() for
109          * subsequent probes, so we just handle
110          * it here.
111          */

112         if (isOpen)
113         {
114             reopenCore();
115             return;
116         }
117
118         beginTime = getCurrentTimeMillis();
119
120         source.openCore();
121
122         /* Notify StatementContext about ourself so that we can
123          * get closed down, if necessary, on an exception.
124          */

125         if (statementContext == null)
126         {
127             statementContext = getLanguageConnectionContext().getStatementContext();
128         }
129         statementContext.setSubqueryResultSet(subqueryNumber, this,
130                                               activation.getNumSubqueries());
131
132         numOpens++;
133         isOpen = true;
134         openTime += getElapsedMillis(beginTime);
135     }
136
137     /**
138      * reopen a scan on the table. scan parameters are evaluated
139      * at each open, so there is probably some way of altering
140      * their values...
141      *
142      * @exception StandardException thrown if cursor finished.
143      */

144     public void reopenCore() throws StandardException
145     {
146         beginTime = getCurrentTimeMillis();
147         if (SanityManager.DEBUG)
148             SanityManager.ASSERT(isOpen, "OnceResultSet already open");
149
150         source.reopenCore();
151         numOpens++;
152
153         openTime += getElapsedMillis(beginTime);
154     }
155
156     /**
157      * Return the requested value computed from the next row.
158      *
159      * @exception StandardException thrown on failure.
160      * StandardException ScalarSubqueryCardinalityViolation
161      * Thrown if scalar subquery returns more than 1 row.
162      */

163     public ExecRow getNextRowCore() throws StandardException
164     {
165         ExecRow candidateRow = null;
166         ExecRow secondRow = null;
167         ExecRow result = null;
168
169         beginTime = getCurrentTimeMillis();
170         // This is an ASSERT and not a real error because this is never
171
// outermost in the tree and so a next call when closed will not occur.
172
if (SanityManager.DEBUG)
173             SanityManager.ASSERT( isOpen, "OpenResultSet not open");
174
175         if ( isOpen )
176         {
177             candidateRow = source.getNextRowCore();
178
179             if (candidateRow != null)
180             {
181                 switch (cardinalityCheck)
182                 {
183                     case DO_CARDINALITY_CHECK:
184                     case NO_CARDINALITY_CHECK:
185                         candidateRow = candidateRow.getClone();
186                         if (cardinalityCheck == DO_CARDINALITY_CHECK)
187                         {
188                             /* Raise an error if the subquery returns > 1 row
189                              * We need to make a copy of the current candidateRow since
190                              * the getNextRow() for this check will wipe out the underlying
191                              * row.
192                              */

193                             secondRow = source.getNextRowCore();
194                             if (secondRow != null)
195                             {
196                                 close();
197                                 StandardException se = StandardException.newException(SQLState.LANG_SCALAR_SUBQUERY_CARDINALITY_VIOLATION);
198                                 throw se;
199                             }
200                         }
201                         result = candidateRow;
202                         break;
203
204                     case UNIQUE_CARDINALITY_CHECK:
205                         candidateRow = candidateRow.getClone();
206                         secondRow = source.getNextRowCore();
207                         DataValueDescriptor orderable1 = candidateRow.getColumn(1);
208                         while (secondRow != null)
209                         {
210                             DataValueDescriptor orderable2 = secondRow.getColumn(1);
211                             if (! (orderable1.compare(DataValueDescriptor.ORDER_OP_EQUALS, orderable2, true, true)))
212                             {
213                                 close();
214                                 StandardException se = StandardException.newException(SQLState.LANG_SCALAR_SUBQUERY_CARDINALITY_VIOLATION);
215                                 throw se;
216                             }
217                             secondRow = source.getNextRowCore();
218                         }
219                         result = candidateRow;
220                         break;
221
222                     default:
223                         if (SanityManager.DEBUG)
224                         {
225                             SanityManager.THROWASSERT(
226                                 "cardinalityCheck not unexpected to be " +
227                                 cardinalityCheck);
228                         }
229                         break;
230                 }
231             }
232             else if (rowWithNulls == null)
233             {
234                 rowWithNulls = (ExecRow) emptyRowFun.invoke(activation);
235                 result = rowWithNulls;
236             }
237             else
238             {
239                 result = rowWithNulls;
240             }
241         }
242
243         currentRow = result;
244         setCurrentRow(result);
245         rowsSeen++;
246
247         nextTime += getElapsedMillis(beginTime);
248         return result;
249     }
250
251     /**
252      * If the result set has been opened,
253      * close the open scan.
254      *
255      * @exception StandardException thrown on error
256      */

257     public void close() throws StandardException
258     {
259         beginTime = getCurrentTimeMillis();
260         if ( isOpen )
261         {
262             // we don't want to keep around a pointer to the
263
// row ... so it can be thrown away.
264
// REVISIT: does this need to be in a finally
265
// block, to ensure that it is executed?
266
clearCurrentRow();
267
268             source.close();
269
270             super.close();
271         }
272         else
273             if (SanityManager.DEBUG)
274                 SanityManager.DEBUG("CloseRepeatInfo","Close of OnceResultSet repeated");
275
276         closeTime += getElapsedMillis(beginTime);
277     }
278
279     /**
280      * @see NoPutResultSet#getPointOfAttachment
281      */

282     public int getPointOfAttachment()
283     {
284         return pointOfAttachment;
285     }
286
287     /**
288      * Return the total amount of time spent in this ResultSet
289      *
290      * @param type CURRENT_RESULTSET_ONLY - time spent only in this ResultSet
291      * ENTIRE_RESULTSET_TREE - time spent in this ResultSet and below.
292      *
293      * @return long The total amount of time spent (in milliseconds).
294      */

295     public long getTimeSpent(int type)
296     {
297         long totTime = constructorTime + openTime + nextTime + closeTime;
298
299         if (type == NoPutResultSet.CURRENT_RESULTSET_ONLY)
300         {
301             return totTime - source.getTimeSpent(ENTIRE_RESULTSET_TREE);
302         }
303         else
304         {
305             return totTime;
306         }
307     }
308 }
309
Popular Tags