1 | /* |
2 | |
3 | Derby - Class org.apache.derby.client.net.NetResultSet |
4 | |
5 | Copyright (c) 2001, 2005 The Apache Software Foundation or its licensors, where applicable. |
6 | |
7 | Licensed under the Apache License, Version 2.0 (the "License"); |
8 | you may not use this file except in compliance with the License. |
9 | You may obtain a copy of the License at |
10 | |
11 | http://www.apache.org/licenses/LICENSE-2.0 |
12 | |
13 | Unless required by applicable law or agreed to in writing, software |
14 | distributed under the License is distributed on an "AS IS" BASIS, |
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
16 | See the License for the specific language governing permissions and |
17 | limitations under the License. |
18 | |
19 | */ |
20 | package org.apache.derby.client.net; |
21 | |
22 | import org.apache.derby.client.am.Cursor; |
23 | import org.apache.derby.client.am.DisconnectException; |
24 | import org.apache.derby.client.am.Section; |
25 | import org.apache.derby.client.am.SqlException; |
26 | |
27 | |
28 | public class NetResultSet extends org.apache.derby.client.am.ResultSet { |
29 | // Alias for (NetConnection) super.statement.connection |
30 | private final NetConnection netConnection_; |
31 | |
32 | // Alias for (NetStatement) super.statement |
33 | private final NetStatement netStatement_; |
34 | |
35 | // Alias for (NetCursor) super.cursor |
36 | final NetCursor netCursor_; |
37 | |
38 | // Alias for (NetAgent) super.agent |
39 | final private NetAgent netAgent_; |
40 | |
41 | // Indicates whether the fixed row protocol is being used. If so, |
42 | // the fetch size will always be 1. |
43 | private boolean isFixedRowProtocol = false; |
44 | |
45 | //-----------------------------state------------------------------------------ |
46 | |
47 | // This is used to avoid sending multiple outovr over subsequent next()'s |
48 | public boolean firstOutovrBuilt_ = false; |
49 | |
50 | //---------------------constructors/finalizer--------------------------------- |
51 | |
52 | // parseOpnqrym() is called right after this constructor is called. |
53 | |
54 | NetResultSet(NetAgent netAgent, |
55 | NetStatement netStatement, |
56 | Cursor cursor, |
57 | int qryprctyp, //protocolType, CodePoint.FIXROWPRC | |
58 | // CodePoint.LMTBLKPRC |
59 | int sqlcsrhld, // holdOption, 0xF0 for false (default) | 0xF1 for true. |
60 | int qryattscr, // scrollOption, 0xF0 for false (default) | 0xF1 for true. |
61 | int qryattsns, // sensitivity, CodePoint.QRYUNK | |
62 | // CodePoint.QRYINS | |
63 | // CodePoint.QRYSNSSTC |
64 | int qryattset, // rowsetCursor, 0xF0 for false (default) | 0xF1 for true. |
65 | long qryinsid, // instanceIdentifier, 0 (if not returned, check default) or number |
66 | int actualResultSetType, |
67 | int actualResultSetConcurrency, |
68 | int actualResultSetHoldability) //throws DisconnectException |
69 | { |
70 | super(netAgent, |
71 | netStatement.statement_, |
72 | //new NetCursor (netAgent, qryprctyp), |
73 | cursor, |
74 | // call the constructor with the real resultSetType and resultSetConcurrency |
75 | // returned from the server |
76 | actualResultSetType, |
77 | actualResultSetConcurrency, |
78 | actualResultSetHoldability); |
79 | |
80 | netAgent_ = netAgent; |
81 | |
82 | // Set up cheat-links |
83 | netCursor_ = (NetCursor) cursor_; |
84 | netStatement_ = netStatement; |
85 | netConnection_ = netStatement.netConnection_; |
86 | |
87 | netCursor_.netResultSet_ = this; |
88 | |
89 | cursorHold_ = (sqlcsrhld != 0xf0); |
90 | if (qryattscr == 0xF1) { |
91 | scrollable_ = true; |
92 | } |
93 | |
94 | // The number of rows returned by the server will always be 1 when the |
95 | // Fixed Row Protocol is being used. |
96 | if (qryprctyp == CodePoint.FIXROWPRC) { |
97 | isFixedRowProtocol = true; |
98 | fetchSize_ = 1; |
99 | } else { |
100 | fetchSize_ = suggestedFetchSize_; |
101 | } |
102 | |
103 | switch (qryattsns) { |
104 | case CodePoint.QRYUNK: |
105 | sensitivity_ = sensitivity_unknown__; |
106 | break; |
107 | case CodePoint.QRYINS: |
108 | sensitivity_ = sensitivity_insensitive__; |
109 | break; |
110 | case CodePoint.QRYSNSSTC: |
111 | sensitivity_ = sensitivity_sensitive_static__; |
112 | break; |
113 | default: // shouldn't happen |
114 | break; |
115 | } |
116 | |
117 | if (qryattset == 0xF1) { |
118 | isRowsetCursor_ = true; |
119 | } |
120 | |
121 | queryInstanceIdentifier_ = qryinsid; |
122 | nestingLevel_ = (int) ((queryInstanceIdentifier_ >>> 48) & 0xFFFF); |
123 | } |
124 | |
125 | |
126 | //-------------------------------flow methods--------------------------------- |
127 | |
128 | // Go through the QRYDTA's received, and calculate the column offsets for each row. |
129 | protected void parseRowset_() throws SqlException { |
130 | int row = 0; |
131 | // Parse all the rows received in the rowset |
132 | // The index we are passing will keep track of which row in the rowset we are parsing |
133 | // so we can reuse the columnDataPosition/Length/IsNull arrays. |
134 | while (netCursor_.calculateColumnOffsetsForRow_(row, true)) { |
135 | rowsReceivedInCurrentRowset_++; |
136 | row++; |
137 | } |
138 | |
139 | // if rowset is not complete and an endqryrm was received, will skip the while loop |
140 | // and go to the checkAndThrow method. otherwise flow an cntqry to try to complete |
141 | // the rowset. |
142 | // -- there is no need to complete the rowset for rowset cursors. fetching stops when |
143 | // the end of data is returned or when an error occurs. all successfully fetched rows |
144 | // are returned to the user. the specific error is not returned until the next fetch. |
145 | while (rowsReceivedInCurrentRowset_ != fetchSize_ && |
146 | !netCursor_.allRowsReceivedFromServer() && !isRowsetCursor_ && |
147 | sensitivity_ != sensitivity_sensitive_dynamic__ && |
148 | sensitivity_ != sensitivity_sensitive_static__) { |
149 | flowFetchToCompleteRowset(); |
150 | while (netCursor_.calculateColumnOffsetsForRow_(row, true)) { |
151 | rowsReceivedInCurrentRowset_++; |
152 | row++; |
153 | } |
154 | } |
155 | checkAndThrowReceivedQueryTerminatingException(); |
156 | } |
157 | |
158 | public void setFetchSize_(int rows) { |
159 | // Do not change the fetchSize for Fixed Row Protocol |
160 | suggestedFetchSize_ = (rows == 0) ? 64 : rows; |
161 | if (!isFixedRowProtocol) { |
162 | fetchSize_ = suggestedFetchSize_; |
163 | } |
164 | } |
165 | |
166 | //-----------------------------helper methods--------------------------------- |
167 | |
168 | void flowFetchToCompleteRowset() throws DisconnectException { |
169 | try { |
170 | agent_.beginWriteChain(statement_); |
171 | |
172 | writeScrollableFetch_((generatedSection_ == null) ? statement_.section_ : generatedSection_, |
173 | fetchSize_ - rowsReceivedInCurrentRowset_, |
174 | scrollOrientation_relative__, |
175 | 1, |
176 | false); // false means do not disard pending |
177 | // partial row and pending query blocks |
178 | |
179 | agent_.flow(statement_); |
180 | readScrollableFetch_(); |
181 | agent_.endReadChain(); |
182 | } catch (SqlException e) { |
183 | throw new DisconnectException(agent_, e); |
184 | } |
185 | } |
186 | |
187 | void queryDataWasReturnedOnOpen() throws DisconnectException { |
188 | } |
189 | |
190 | // ------------------------------- abstract box car methods -------------------------------------- |
191 | public void writeFetch_(Section section) throws SqlException { |
192 | if (resultSetType_ == java.sql.ResultSet.TYPE_FORWARD_ONLY && fetchSize_ != 0 && |
193 | rowsYetToBeReceivedForRowset_ > 0) { |
194 | netAgent_.resultSetRequest_.writeFetch(this, |
195 | section, |
196 | rowsYetToBeReceivedForRowset_); |
197 | } else { |
198 | netAgent_.resultSetRequest_.writeFetch(this, |
199 | section, |
200 | fetchSize_); |
201 | } |
202 | } |
203 | |
204 | public void readFetch_() throws SqlException { |
205 | netAgent_.resultSetReply_.readFetch(this); |
206 | } |
207 | |
208 | public void writeScrollableFetch_(Section section, |
209 | int fetchSize, |
210 | int orientation, |
211 | long rowToFetch, |
212 | boolean resetQueryBlocks) throws SqlException { |
213 | netAgent_.resultSetRequest_.writeScrollableFetch(this, |
214 | section, |
215 | fetchSize, |
216 | orientation, |
217 | rowToFetch, |
218 | resetQueryBlocks); |
219 | } |
220 | |
221 | // think about splitting out the position cursor stuff from the fetch stuff |
222 | // use commented out abstract position cursor methods above |
223 | public void readScrollableFetch_() throws SqlException { |
224 | netAgent_.resultSetReply_.readScrollableFetch(this); |
225 | } |
226 | |
227 | public void writePositioningFetch_(Section section, |
228 | int orientation, |
229 | long rowToFetch) throws SqlException { |
230 | netAgent_.resultSetRequest_.writePositioningFetch(this, |
231 | section, |
232 | orientation, |
233 | rowToFetch); |
234 | } |
235 | |
236 | public void readPositioningFetch_() throws SqlException { |
237 | netAgent_.resultSetReply_.readPositioningFetch(this); |
238 | } |
239 | |
240 | public void writeCursorClose_(Section section) throws SqlException { |
241 | netAgent_.resultSetRequest_.writeCursorClose(this, section); |
242 | } |
243 | |
244 | public void readCursorClose_() throws SqlException { |
245 | netAgent_.resultSetReply_.readCursorClose(this); |
246 | } |
247 | |
248 | /** |
249 | * Method that is invoked by <code>closeX()</code> before the |
250 | * result set is actually being closed. If QRYCLSIMP is enabled on |
251 | * the cursor, scan data buffer for end of data (SQL state |
252 | * 02000). If end of data is received, the result set is closed on |
253 | * the server. |
254 | * |
255 | * @exception SqlException |
256 | */ |
257 | protected void preClose_() throws SqlException { |
258 | if (netCursor_.getQryclsimpEnabled()) { |
259 | netCursor_.scanDataBufferForEndOfData(); |
260 | } |
261 | } |
262 | } |