KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2
3    Derby - Class org.apache.derby.impl.sql.execute.NormalizeResultSet
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.Activation;
32 import org.apache.derby.iapi.sql.ResultDescription;
33 import org.apache.derby.iapi.sql.ResultSet;
34 import org.apache.derby.iapi.sql.ResultColumnDescriptor;
35 import org.apache.derby.iapi.types.TypeId;
36
37 import org.apache.derby.iapi.types.DataValueDescriptor;
38 import org.apache.derby.iapi.types.DataTypeDescriptor;
39 import org.apache.derby.iapi.types.RowLocation;
40
41
42 import org.apache.derby.iapi.sql.execute.CursorResultSet;
43 import org.apache.derby.iapi.sql.execute.ExecRow;
44 import org.apache.derby.iapi.sql.execute.ExecutionContext;
45 import org.apache.derby.iapi.sql.execute.NoPutResultSet;
46
47 import org.apache.derby.iapi.services.loader.GeneratedMethod;
48
49 import org.apache.derby.iapi.error.StandardException;
50 import org.apache.derby.iapi.reference.SQLState;
51
52 /**
53  * Cast the rows from the source result set to match the format of the
54  * result set for the entire statement.
55  */

56
57 class NormalizeResultSet extends NoPutResultSetImpl
58     implements CursorResultSet
59 {
60     /*
61     ** Set in constructor and not altered during life of object.
62     */

63
64     public NoPutResultSet source;
65     private ExecRow normalizedRow;
66     private int numCols;
67     private int startCol;
68
69     /* RESOLVE - We need to pass the ResultDescription for this ResultSet
70      * as a parameter to the constructor and use it instead of the one from
71      * the activation
72      */

73     private ResultDescription resultDescription;
74
75     /* info for caching DTSs */
76     private DataTypeDescriptor[] desiredTypes;
77
78     /**
79      * Constructor for a NormalizeResultSet
80      *
81      * @param source The NoPutResultSet from which to get rows
82      * to be normalized
83      * @param activation The activation for this execution
84      * @param resultSetNumber The resultSetNumber
85      * @param erdNumber The integer for the ResultDescription
86      *
87      * @exception StandardException on error
88      */

89
90     public NormalizeResultSet(NoPutResultSet source,
91                               Activation activation, int resultSetNumber,
92                               int erdNumber,
93                               double optimizerEstimatedRowCount,
94                               double optimizerEstimatedCost,
95                               boolean forUpdate) throws StandardException
96     {
97         super(activation, resultSetNumber, optimizerEstimatedRowCount,
98               optimizerEstimatedCost);
99         this.source = source;
100
101         if (SanityManager.DEBUG)
102         {
103             if (! (activation.getPreparedStatement().getSavedObject(erdNumber)
104                              instanceof ResultDescription))
105             {
106                 SanityManager.THROWASSERT(
107                     "activation.getPreparedStatement().getSavedObject(erdNumber) " +
108                     "expected to be instanceof ResultDescription");
109             }
110
111             // source expected to be non-null, mystery stress test bug
112
// - sometimes get NullPointerException in openCore().
113
SanityManager.ASSERT(source != null,
114                 "NRS(), source expected to be non-null");
115         }
116
117         this.resultDescription =
118             (ResultDescription) activation.getPreparedStatement().getSavedObject(erdNumber);
119
120         numCols = resultDescription.getColumnCount();
121         
122         /*
123           An update row, for an update statement which sets n columns; i.e
124              UPDATE tab set x,y,z=.... where ...;
125           has,
126           before values of x,y,z after values of x,y,z and rowlocation.
127           need only normalize after values of x,y,z.
128           i.e insead of starting at index = 1, I need to start at index = 4.
129           also I needn't normalize the last value in the row.
130     */

131         startCol = (forUpdate) ? ((numCols - 1)/ 2) + 1 : 1;
132         normalizedRow = activation.getExecutionFactory().getValueRow(numCols);
133         constructorTime += getElapsedMillis(beginTime);
134     }
135
136
137     //
138
// ResultSet interface (leftover from NoPutResultSet)
139
//
140

141     /**
142      * open a scan on the source. scan parameters are evaluated
143      * at each open, so there is probably some way of altering
144      * their values...
145      *
146      * @exception StandardException thrown on failure
147      */

148     public void openCore() throws StandardException
149     {
150         beginTime = getCurrentTimeMillis();
151         if (SanityManager.DEBUG)
152             SanityManager.ASSERT( ! isOpen, "NormalizeResultSet already open");
153
154         // source expected to be non-null, mystery stress test bug
155
// - sometimes get NullPointerException in openCore().
156
if (SanityManager.DEBUG)
157         {
158             SanityManager.ASSERT(source != null,
159                 "NRS().openCore(), source expected to be non-null");
160         }
161
162         source.openCore();
163         isOpen = true;
164         numOpens++;
165
166         openTime += getElapsedMillis(beginTime);
167     }
168
169     /**
170      * reopen a scan on the table. scan parameters are evaluated
171      * at each open, so there is probably some way of altering
172      * their values...
173      *
174      * @exception StandardException thrown if cursor finished.
175      */

176     public void reopenCore() throws StandardException
177     {
178         beginTime = getCurrentTimeMillis();
179         if (SanityManager.DEBUG)
180             SanityManager.ASSERT(isOpen, "NormalizeResultSet already open");
181
182         source.reopenCore();
183         numOpens++;
184
185         openTime += getElapsedMillis(beginTime);
186     }
187
188     /**
189      *
190      * @exception StandardException thrown on failure
191      */

192     public ExecRow getNextRowCore() throws StandardException
193     {
194         ExecRow sourceRow = null;
195         ExecRow result = null;
196
197         beginTime = getCurrentTimeMillis();
198         if (!isOpen)
199             throw StandardException.newException(SQLState.LANG_RESULT_SET_NOT_OPEN, "next");
200
201         sourceRow = source.getNextRowCore();
202         if (sourceRow != null)
203         {
204             result = normalizeRow(sourceRow);
205             rowsSeen++;
206         }
207
208         currentRow = result;
209         setCurrentRow(result);
210
211         nextTime += getElapsedMillis(beginTime);
212         return result;
213     }
214
215     /**
216      * If the result set has been opened,
217      * close the open scan.
218      *
219      * @exception StandardException thrown on error
220      */

221     public void close() throws StandardException
222     {
223         beginTime = getCurrentTimeMillis();
224         if ( isOpen )
225         {
226             currentRow = null;
227             source.close();
228
229             super.close();
230         }
231         else
232             if (SanityManager.DEBUG)
233                 SanityManager.DEBUG("CloseRepeatInfo","Close of NormalizeResultSet repeated");
234
235         closeTime += getElapsedMillis(beginTime);
236     }
237
238     /**
239      * Return the total amount of time spent in this ResultSet
240      *
241      * @param type CURRENT_RESULTSET_ONLY - time spent only in this ResultSet
242      * ENTIRE_RESULTSET_TREE - time spent in this ResultSet and below.
243      *
244      * @return long The total amount of time spent (in milliseconds).
245      */

246     public long getTimeSpent(int type)
247     {
248         long totTime = constructorTime + openTime + nextTime + closeTime;
249
250         if (type == NoPutResultSet.CURRENT_RESULTSET_ONLY)
251         {
252             return totTime - source.getTimeSpent(ENTIRE_RESULTSET_TREE);
253         }
254         else
255         {
256             return totTime;
257         }
258     }
259
260     //
261
// CursorResultSet interface
262
//
263

264     /**
265      * Gets information from its source. We might want
266      * to have this take a CursorResultSet in its constructor some day,
267      * instead of doing a cast here?
268      *
269      * @see CursorResultSet
270      *
271      * @return the row location of the current cursor row.
272      *
273      * @exception StandardException thrown on failure
274      */

275     public RowLocation getRowLocation() throws StandardException
276     {
277         if (SanityManager.DEBUG)
278             SanityManager.ASSERT(source instanceof CursorResultSet, "source is not a cursorresultset");
279         return ( (CursorResultSet)source ).getRowLocation();
280     }
281
282     /**
283      * Gets information from last getNextRow call.
284      *
285      * @see CursorResultSet
286      *
287      * @return the last row returned.
288      */

289     /* RESOLVE - this should return activation.getCurrentRow(resultSetNumber),
290      * once there is such a method. (currentRow is redundant)
291      */

292     public ExecRow getCurrentRow()
293     {
294         return currentRow;
295     }
296
297     //
298
// class implementation
299
//
300
/**
301      * Normalize a row. For now, this means calling constructors through
302      * the type services to normalize a type to itself. For example,
303      * if you're putting a char(30) value into a char(15) column, it
304      * calls a SQLChar constructor with the char(30) value, and the
305      * constructor truncates the value and makes sure that no non-blank
306      * characters are truncated.
307      *
308      * In the future, this mechanism will be extended to do type conversions,
309      * as well. I didn't implement type conversions yet because it looks
310      * like a lot of work, and we needed char and varchar right away.
311      *
312      * @param sourceRow The row to normalize
313      *
314      * @return The normalized row
315      *
316      * @exception StandardException thrown on failure
317      */

318     private ExecRow normalizeRow(ExecRow sourceRow) throws StandardException
319     {
320         int whichCol;
321
322         if (desiredTypes == null)
323         {
324             desiredTypes = new DataTypeDescriptor[numCols];
325             for (whichCol = 1; whichCol <= numCols; whichCol++)
326             {
327                 DataTypeDescriptor dtd = resultDescription.getColumnDescriptor(whichCol).getType();
328
329                 desiredTypes[whichCol - 1] = dtd;
330             }
331
332         }
333
334         for (whichCol = 1; whichCol <= numCols; whichCol++)
335         {
336             DataValueDescriptor sourceCol = sourceRow.getColumn(whichCol);
337             if (sourceCol != null)
338             {
339                 DataValueDescriptor normalizedCol;
340                 // skip the before values in case of update
341
if (whichCol < startCol)
342                     normalizedCol = sourceCol;
343                 else
344                     try {
345                         normalizedCol =
346                         desiredTypes[whichCol - 1].normalize(sourceCol,
347                                     normalizedRow.getColumn(whichCol));
348                     } catch (StandardException se) {
349                         // Catch illegal null insert and add column info
350
if (se.getMessageId().startsWith(SQLState.LANG_NULL_INTO_NON_NULL))
351                         {
352                             ResultColumnDescriptor columnDescriptor =
353                                 resultDescription.getColumnDescriptor(whichCol);
354                             throw
355                                 StandardException.newException(SQLState.LANG_NULL_INTO_NON_NULL,
356                                                                columnDescriptor.getName());
357                         }
358                         //just rethrow if not LANG_NULL_INTO_NON_NULL
359
throw se;
360                     }
361
362                 normalizedRow.setColumn(whichCol, normalizedCol);
363             }
364         }
365
366         return normalizedRow;
367     }
368
369     /**
370      * @see NoPutResultSet#updateRow
371      */

372     public void updateRow (ExecRow row) throws StandardException {
373         source.updateRow(row);
374     }
375
376     /**
377      * @see NoPutResultSet#markRowAsDeleted
378      */

379     public void markRowAsDeleted() throws StandardException {
380         source.markRowAsDeleted();
381     }
382
383 }
384
Popular Tags