KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2
3    Derby - Class org.apache.derby.impl.sql.execute.CurrentOfResultSet
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.sql.execute.CursorResultSet;
25 import org.apache.derby.iapi.error.StandardException;
26 import org.apache.derby.iapi.reference.SQLState;
27
28 import org.apache.derby.iapi.sql.execute.CursorActivation;
29 import org.apache.derby.iapi.sql.execute.ExecRow;
30 import org.apache.derby.iapi.sql.execute.NoPutResultSet;
31
32 import org.apache.derby.iapi.sql.Activation;
33 import org.apache.derby.iapi.sql.ResultSet;
34 import org.apache.derby.iapi.sql.PreparedStatement;
35
36 import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
37
38 import org.apache.derby.iapi.types.RowLocation;
39
40 import org.apache.derby.iapi.services.sanity.SanityManager;
41 import org.apache.derby.iapi.sql.depend.DependencyManager;
42
43 /**
44  * Takes a cursor name and returns the current row
45  * of the cursor; for use in generating the source
46  * row and row location for positioned update/delete operations.
47  * <p>
48  * This result set returns only one row.
49  *
50  * @author ames
51  */

52 public class CurrentOfResultSet extends NoPutResultSetImpl
53     implements CursorResultSet {
54
55     private boolean next;
56     private RowLocation rowLocation;
57
58     private CursorResultSet cursor;
59     private CursorResultSet target;
60     private ExecRow sparseRow;
61
62     // set in constructor and not altered during
63
// life of object.
64
private final String JavaDoc cursorName;
65     private final String JavaDoc psName;
66
67     //
68
// class interface
69
//
70
public CurrentOfResultSet(String JavaDoc cursorName, Activation activation,
71                               int resultSetNumber, String JavaDoc psName)
72     {
73         super(activation, resultSetNumber, 0.0d, 0.0d);
74         if (SanityManager.DEBUG)
75             SanityManager.ASSERT( cursorName!=null, "current of scan must get cursor name");
76         this.cursorName = cursorName;
77         this.psName = psName;
78     }
79
80     //
81
// ResultSet interface (leftover from NoPutResultSet)
82
//
83
/**
84      * open a scan on the table. scan parameters are evaluated
85      * at each open, so there is probably some way of altering
86      * their values...
87      *
88      * @exception StandardException thrown on failure to open
89      */

90     public void openCore() throws StandardException {
91         if (SanityManager.DEBUG)
92             SanityManager.ASSERT( ! isOpen, "CurrentOfResultSet already open");
93
94         // get the cursor
95
getCursor();
96
97         next = false;
98         isOpen = true;
99     }
100
101     /**
102      * If open and not returned yet, returns the row.
103      *
104      * @exception StandardException thrown on failure.
105      */

106     public ExecRow getNextRowCore() throws StandardException {
107
108         if ( isOpen ) {
109             if ( ! next ) {
110                 next = true;
111                 if (SanityManager.DEBUG)
112                     SanityManager.ASSERT(! cursor.isClosed(), "cursor closed");
113
114                 ExecRow cursorRow = cursor.getCurrentRow();
115
116                 // requalify the current row
117
if (cursorRow == null) {
118                     throw StandardException.newException(SQLState.NO_CURRENT_ROW);
119                 }
120                 // we know it will be requested, may as well get it now.
121
rowLocation = cursor.getRowLocation();
122
123                 // get the row from the base table, which is the real result
124
// row for the CurrentOfResultSet
125
currentRow = target.getCurrentRow();
126
127                 // if the source result set is a ScrollInsensitiveResultSet, and
128
// the current row has been deleted (while the cursor was
129
// opened), the cursor result set (scroll insensitive) will
130
// return the cached row, while the target result set will
131
// return null (row has been deleted under owr feet).
132
if (rowLocation == null ||
133                         (cursorRow != null && currentRow == null)) {
134                     activation.addWarning(StandardException.
135                             newWarning(SQLState.CURSOR_OPERATION_CONFLICT));
136                     return null;
137                 }
138
139                 /* beetle 3865: updateable cursor using index. If underlying is a covering
140                  * index, target is a TableScanRS (instead of a IndexRow2BaseRowRS) for the
141                  * index scan. But the problem is it returns a compact row in index key order.
142                  * However the ProjectRestrictRS above us that sets up the old and new column
143                  * values expects us to return a sparse row in heap order. We have to do the
144                  * wiring here, since we don't have IndexRow2BaseRowRS to do this work. This
145                  * problem was not exposed before, because we never used index scan for updateable
146                  * cursors.
147                  */

148                 if (target instanceof TableScanResultSet)
149                 {
150                     TableScanResultSet scan = (TableScanResultSet) target;
151                     if (scan.indexCols != null && currentRow != null)
152                         currentRow = getSparseRow(currentRow, scan.indexCols);
153                 }
154                 /* If we are updating rows from cached RIDs, we should compare with forward-most
155                  * scan key when deciding whether to add RID to hash table or not.
156                  */

157                 TableScanResultSet scan = (TableScanResultSet) activation.getForUpdateIndexScan();
158                 if (scan != null)
159                 {
160                     if (target instanceof IndexRowToBaseRowResultSet)
161                         scan.compareToLastKey = ((IndexRowToBaseRowResultSet) target).currentRowPrescanned;
162                     else if (target instanceof TableScanResultSet)
163                         scan.compareToLastKey = ((TableScanResultSet) target).currentRowPrescanned;
164                 }
165
166                 // REMIND: verify the row is still there
167
// at present we get an ugly exception from the store,
168
// Hopefully someday we can just do this:
169
//
170
// if (!rowLocation.rowExists())
171
// throw StandardException.newException(SQLState.LANG_NO_CURRENT_ROW, cursorName);
172
}
173             else {
174                 currentRow = null;
175                 rowLocation = null;
176             }
177         }
178         else {
179             currentRow = null;
180             rowLocation = null;
181         }
182         setCurrentRow(currentRow);
183         return currentRow;
184     }
185
186     /**
187      * Return a sparse heap row, based on a compact index row.
188      *
189      * @param row compact referenced index row
190      * @param indexCols base column positions of index keys, signed with asc/desc info
191      *
192      * @return a sparse heap row with referenced columns
193      */

194     private ExecRow getSparseRow(ExecRow row, int[] indexCols) throws StandardException
195     {
196         int colPos;
197         if (sparseRow == null)
198         {
199             int numCols = 1;
200             for (int i = 0; i < indexCols.length; i++)
201             {
202                 colPos = (indexCols[i] > 0) ? indexCols[i] : -indexCols[i];
203                 if (colPos > numCols)
204                     numCols = colPos;
205             }
206             sparseRow = new ValueRow(numCols);
207         }
208         for (int i = 1; i <= indexCols.length; i++)
209         {
210             colPos = (indexCols[i-1] > 0) ? indexCols[i-1] : -indexCols[i-1];
211             sparseRow.setColumn(colPos, row.getColumn(i));
212         }
213
214         return sparseRow;
215     }
216
217     /**
218      * If the result set has been opened,
219      * close the open scan.
220      *
221      * @exception StandardException thrown on error
222      */

223     public void close() throws StandardException
224     {
225         if ( isOpen ) {
226             // we don't want to keep around a pointer to the
227
// row ... so it can be thrown away.
228
// REVISIT: does this need to be in a finally
229
// block, to ensure that it is executed?
230
clearCurrentRow();
231             next = false;
232
233             super.close();
234         }
235         else
236             if (SanityManager.DEBUG)
237                 SanityManager.DEBUG("CloseRepeatInfo","Close of CurrentOfResultSet repeated");
238     }
239     public void finish() throws StandardException
240     {
241         finishAndRTS();
242     }
243
244     /**
245      * Return the total amount of time spent in this ResultSet
246      *
247      * @param type CURRENT_RESULTSET_ONLY - time spent only in this ResultSet
248      * ENTIRE_RESULTSET_TREE - time spent in this ResultSet and below.
249      *
250      * @return long The total amount of time spent (in milliseconds).
251      */

252     public long getTimeSpent(int type)
253     {
254         /* RESOLVE - RunTimeStats not implemented yet */
255         return 0;
256     }
257
258     /**
259      * This result set has its row location from
260      * the last fetch done. If it is closed,
261      * a null is returned.
262      *
263      * @see CursorResultSet
264      *
265      * @return the row location of the current row.
266      * @exception StandardException thrown on failure to get row location
267      */

268     public RowLocation getRowLocation() {
269         return rowLocation;
270     }
271
272     /**
273      * @see CursorResultSet
274      *
275      * @return the last row returned by getNextRow.
276      */

277     public ExecRow getCurrentRow() {
278         return currentRow;
279     }
280
281     //
282
// class implementation
283
//
284
/**
285         Because the positioned operation only gets one location
286         per execution, and the cursor could be completely different
287         for each execution (closed and reopened, perhaps), we
288         determine where caching the cursor could be applied.
289         <p>
290         When cached, we check if the cursor was closed'd,
291         and if so, throw it out and
292         see if there's one in the cache with our name.
293
294      */

295     private void getCursor() throws StandardException {
296
297         // need to look again if cursor was closed
298
if (cursor != null) {
299             if (cursor.isClosed())
300             {
301                 cursor = null;
302                 target = null;
303             }
304         }
305
306         if (cursor == null) {
307
308             LanguageConnectionContext lcc = getLanguageConnectionContext();
309
310             CursorActivation cursorActivation = lcc.lookupCursorActivation(cursorName);
311
312             if (cursorActivation != null)
313             {
314                 
315                 cursor = cursorActivation.getCursorResultSet();
316                 target = cursorActivation.getTargetResultSet();
317                 /* beetle 3865: updateable cursor using index. 2 way communication between
318                  * update activation and cursor activation. Cursor passes index scan to
319                  * update and update passes heap conglom controller to cursor.
320                  */

321                 activation.setForUpdateIndexScan(cursorActivation.getForUpdateIndexScan());
322                 if (cursorActivation.getHeapConglomerateController() != null)
323                     cursorActivation.getHeapConglomerateController().close();
324                 cursorActivation.setHeapConglomerateController(activation.getHeapConglomerateController());
325             }
326         }
327
328         if (cursor == null || cursor.isClosed()) {
329             throw StandardException.newException(SQLState.LANG_CURSOR_CLOSED, cursorName);
330         }
331     }
332
333     /**
334      * @see NoPutResultSet#updateRow
335      */

336     public void updateRow (ExecRow row) throws StandardException {
337         ((NoPutResultSet)cursor).updateRow(row);
338     }
339     
340     /**
341      * @see NoPutResultSet#markRowAsDeleted
342      */

343     public void markRowAsDeleted() throws StandardException {
344         ((NoPutResultSet)cursor).markRowAsDeleted();
345     }
346     
347 }
348
Popular Tags