source: Ballon/out/artifacts/geisa_artifact/WEB-INF/lib/mysql-connector-java-5.1.21/src/com/mysql/jdbc/RowDataCursor.java @ 848

Last change on this file since 848 was 766, checked in by npipsl, 11 years ago
File size: 11.7 KB
Line 
1/*
2 Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
3 
4
5  The MySQL Connector/J is licensed under the terms of the GPLv2
6  <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most MySQL Connectors.
7  There are special exceptions to the terms and conditions of the GPLv2 as it is applied to
8  this software, see the FLOSS License Exception
9  <http://www.mysql.com/about/legal/licensing/foss-exception.html>.
10
11  This program is free software; you can redistribute it and/or modify it under the terms
12  of the GNU General Public License as published by the Free Software Foundation; version 2
13  of the License.
14
15  This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
16  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17  See the GNU General Public License for more details.
18
19  You should have received a copy of the GNU General Public License along with this
20  program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth
21  Floor, Boston, MA 02110-1301  USA
22 */
23
24package com.mysql.jdbc;
25
26import java.sql.SQLException;
27import java.util.ArrayList;
28import java.util.List;
29
30/**
31 * Model for result set data backed by a cursor. Only works for forward-only
32 * result sets (but still works with updatable concurrency).
33 *
34 * @version $Id: CursorRowProvider.java,v 1.1.2.1 2005/05/19 18:31:49 mmatthews
35 *          Exp $
36 */
37public class RowDataCursor implements RowData {
38
39        private final static int BEFORE_START_OF_ROWS = -1;
40
41        /**
42         * The cache of rows we have retrieved from the server.
43         */
44        private List<ResultSetRow> fetchedRows;
45
46        /**
47         * Where we are positionaly in the entire result set, used mostly to
48         * facilitate easy 'isBeforeFirst()' and 'isFirst()' methods.
49         */
50        private int currentPositionInEntireResult = BEFORE_START_OF_ROWS;
51
52        /**
53         * Position in cache of rows, used to determine if we need to fetch more
54         * rows from the server to satisfy a request for the next row.
55         */
56        private int currentPositionInFetchedRows = BEFORE_START_OF_ROWS;
57
58        /**
59         * The result set that we 'belong' to.
60         */
61        private ResultSetImpl owner;
62
63        /**
64         * Have we been told from the server that we have seen the last row?
65         */
66        private boolean lastRowFetched = false;
67
68        /**
69         * Field-level metadata from the server. We need this, because it is not
70         * sent for each batch of rows, but we need the metadata to unpack the
71         * results for each field.
72         */
73        private Field[] metadata;
74
75        /**
76         * Communications channel to the server
77         */
78        private MysqlIO mysql;
79
80        /**
81         * Identifier for the statement that created this cursor.
82         */
83        private long statementIdOnServer;
84
85        /**
86         * The prepared statement that created this cursor.
87         */
88        private ServerPreparedStatement prepStmt;
89
90        /**
91         * The server status for 'last-row-sent'...This might belong in mysqldefs,
92         * but it it only ever referenced from here.
93         */
94        private static final int SERVER_STATUS_LAST_ROW_SENT = 128;
95
96        /**
97         * Have we attempted to fetch any rows yet?
98         */
99        private boolean firstFetchCompleted = false;
100
101        private boolean wasEmpty = false;
102
103        private boolean useBufferRowExplicit = false;
104       
105        /**
106         * Creates a new cursor-backed row provider.
107         *
108         * @param ioChannel
109         *            connection to the server.
110         * @param creatingStatement
111         *            statement that opened the cursor.
112         * @param metadata
113         *            field-level metadata for the results that this cursor covers.
114         */
115        public RowDataCursor(MysqlIO ioChannel,
116                        ServerPreparedStatement creatingStatement, Field[] metadata) {
117                this.currentPositionInEntireResult = BEFORE_START_OF_ROWS;
118                this.metadata = metadata;
119                this.mysql = ioChannel;
120                this.statementIdOnServer = creatingStatement.getServerStatementId();
121                this.prepStmt = creatingStatement;
122                this.useBufferRowExplicit = MysqlIO.useBufferRowExplicit(this.metadata);
123               
124        }
125
126        /**
127         * Returns true if we got the last element.
128         *
129         * @return DOCUMENT ME!
130         */
131        public boolean isAfterLast() {
132                return lastRowFetched
133                                && this.currentPositionInFetchedRows > this.fetchedRows.size();
134        }
135
136        /**
137         * Only works on non dynamic result sets.
138         *
139         * @param index
140         *            row number to get at
141         * @return row data at index
142         * @throws SQLException
143         *             if a database error occurs
144         */
145        public ResultSetRow getAt(int ind) throws SQLException {
146                notSupported();
147
148                return null;
149        }
150
151        /**
152         * Returns if iteration has not occured yet.
153         *
154         * @return true if before first row
155         * @throws SQLException
156         *             if a database error occurs
157         */
158        public boolean isBeforeFirst() throws SQLException {
159                return this.currentPositionInEntireResult < 0;
160        }
161
162        /**
163         * Moves the current position in the result set to the given row number.
164         *
165         * @param rowNumber
166         *            row to move to
167         * @throws SQLException
168         *             if a database error occurs
169         */
170        public void setCurrentRow(int rowNumber) throws SQLException {
171                notSupported();
172        }
173
174        /**
175         * Returns the current position in the result set as a row number.
176         *
177         * @return the current row number
178         * @throws SQLException
179         *             if a database error occurs
180         */
181        public int getCurrentRowNumber() throws SQLException {
182                return this.currentPositionInEntireResult + 1;
183        }
184
185        /**
186         * Returns true if the result set is dynamic.
187         *
188         * This means that move back and move forward won't work because we do not
189         * hold on to the records.
190         *
191         * @return true if this result set is streaming from the server
192         */
193        public boolean isDynamic() {
194                return true;
195        }
196
197        /**
198         * Has no records.
199         *
200         * @return true if no records
201         * @throws SQLException
202         *             if a database error occurs
203         */
204        public boolean isEmpty() throws SQLException {
205                return this.isBeforeFirst() && this.isAfterLast();
206        }
207
208        /**
209         * Are we on the first row of the result set?
210         *
211         * @return true if on first row
212         * @throws SQLException
213         *             if a database error occurs
214         */
215        public boolean isFirst() throws SQLException {
216                return this.currentPositionInEntireResult == 0;
217        }
218
219        /**
220         * Are we on the last row of the result set?
221         *
222         * @return true if on last row
223         * @throws SQLException
224         *             if a database error occurs
225         */
226        public boolean isLast() throws SQLException {
227                return this.lastRowFetched
228                                && this.currentPositionInFetchedRows == (this.fetchedRows
229                                                .size() - 1);
230        }
231
232        /**
233         * Adds a row to this row data.
234         *
235         * @param row
236         *            the row to add
237         * @throws SQLException
238         *             if a database error occurs
239         */
240        public void addRow(ResultSetRow row) throws SQLException {
241                notSupported();
242        }
243
244        /**
245         * Moves to after last.
246         *
247         * @throws SQLException
248         *             if a database error occurs
249         */
250        public void afterLast() throws SQLException {
251                notSupported();
252        }
253
254        /**
255         * Moves to before first.
256         *
257         * @throws SQLException
258         *             if a database error occurs
259         */
260        public void beforeFirst() throws SQLException {
261                notSupported();
262        }
263
264        /**
265         * Moves to before last so next el is the last el.
266         *
267         * @throws SQLException
268         *             if a database error occurs
269         */
270        public void beforeLast() throws SQLException {
271                notSupported();
272        }
273
274        /**
275         * We're done.
276         *
277         * @throws SQLException
278         *             if a database error occurs
279         */
280        public void close() throws SQLException {
281
282                this.metadata = null;
283                this.owner = null;
284        }
285
286        /**
287         * Returns true if another row exists.
288         *
289         * @return true if more rows
290         * @throws SQLException
291         *             if a database error occurs
292         */
293        public boolean hasNext() throws SQLException {
294
295                if (this.fetchedRows != null && this.fetchedRows.size() == 0) {
296                        return false;
297                }
298
299                if (this.owner != null && this.owner.owningStatement != null) {
300                        int maxRows = this.owner.owningStatement.maxRows;
301                       
302                        if (maxRows != -1 && this.currentPositionInEntireResult + 1 > maxRows) {
303                                return false;
304                        }       
305                }
306               
307                if (this.currentPositionInEntireResult != BEFORE_START_OF_ROWS) {
308                        // Case, we've fetched some rows, but are not at end of fetched
309                        // block
310                        if (this.currentPositionInFetchedRows < (this.fetchedRows.size() - 1)) {
311                                return true;
312                        } else if (this.currentPositionInFetchedRows == this.fetchedRows
313                                        .size()
314                                        && this.lastRowFetched) {
315                                return false;
316                        } else {
317                                // need to fetch to determine
318                                fetchMoreRows();
319
320                                return (this.fetchedRows.size() > 0);
321                        }
322                }
323
324                // Okay, no rows _yet_, so fetch 'em
325
326                fetchMoreRows();
327
328                return this.fetchedRows.size() > 0;
329        }
330
331        /**
332         * Moves the current position relative 'rows' from the current position.
333         *
334         * @param rows
335         *            the relative number of rows to move
336         * @throws SQLException
337         *             if a database error occurs
338         */
339        public void moveRowRelative(int rows) throws SQLException {
340                notSupported();
341        }
342
343        /**
344         * Returns the next row.
345         *
346         * @return the next row value
347         * @throws SQLException
348         *             if a database error occurs
349         */
350        public ResultSetRow next() throws SQLException {
351                if (this.fetchedRows == null && this.currentPositionInEntireResult != BEFORE_START_OF_ROWS) {
352                        throw SQLError.createSQLException(
353                                        Messages
354                                                        .getString("ResultSet.Operation_not_allowed_after_ResultSet_closed_144"), //$NON-NLS-1$
355                                        SQLError.SQL_STATE_GENERAL_ERROR, mysql.getExceptionInterceptor());
356                }
357               
358                if (!hasNext()) {
359                        return null;
360                }
361               
362                this.currentPositionInEntireResult++;
363                this.currentPositionInFetchedRows++;
364
365                // Catch the forced scroll-passed-end
366                if (this.fetchedRows != null && this.fetchedRows.size() == 0) {
367                        return null;
368                }
369
370                if (this.currentPositionInFetchedRows > (this.fetchedRows.size() - 1)) {
371                        fetchMoreRows();
372                        this.currentPositionInFetchedRows = 0;
373                }
374
375                ResultSetRow row = this.fetchedRows
376                                .get(this.currentPositionInFetchedRows);
377
378                row.setMetadata(this.metadata);
379               
380                return row;
381        }
382
383        /**
384         *
385         */
386        private void fetchMoreRows() throws SQLException {
387                if (this.lastRowFetched) {
388                        this.fetchedRows = new ArrayList<ResultSetRow>(0);
389                        return;
390                }
391
392                synchronized (this.owner.connection) {
393                        boolean oldFirstFetchCompleted = this.firstFetchCompleted;
394                       
395                        if (!this.firstFetchCompleted) {
396                                this.firstFetchCompleted = true;
397                        }
398
399                        int numRowsToFetch = this.owner.getFetchSize();
400
401                        if (numRowsToFetch == 0) {
402                                numRowsToFetch = this.prepStmt.getFetchSize();
403                        }
404                       
405                        if (numRowsToFetch == Integer.MIN_VALUE) {
406                                // Handle the case where the user used 'old'
407                                // streaming result sets
408
409                                numRowsToFetch = 1;
410                        }
411
412                        this.fetchedRows = this.mysql.fetchRowsViaCursor(this.fetchedRows,
413                                        this.statementIdOnServer, this.metadata, numRowsToFetch, 
414                                        this.useBufferRowExplicit);
415                        this.currentPositionInFetchedRows = BEFORE_START_OF_ROWS;
416
417                        if ((this.mysql.getServerStatus() & SERVER_STATUS_LAST_ROW_SENT) != 0) {
418                                this.lastRowFetched = true;
419                               
420                                if (!oldFirstFetchCompleted && this.fetchedRows.size() == 0) {
421                                        this.wasEmpty  = true;
422                                }
423                        }
424                }
425        }
426
427        /**
428         * Removes the row at the given index.
429         *
430         * @param index
431         *            the row to move to
432         * @throws SQLException
433         *             if a database error occurs
434         */
435        public void removeRow(int ind) throws SQLException {
436                notSupported();
437        }
438
439        /**
440         * Only works on non dynamic result sets.
441         *
442         * @return the size of this row data
443         */
444        public int size() {
445                return RESULT_SET_SIZE_UNKNOWN;
446        }
447
448        protected void nextRecord() throws SQLException {
449
450        }
451
452        private void notSupported() throws SQLException {
453                throw new OperationNotSupportedException();
454        }
455
456        /*
457         * (non-Javadoc)
458         *
459         * @see com.mysql.jdbc.RowProvider#setOwner(com.mysql.jdbc.ResultSet)
460         */
461        public void setOwner(ResultSetImpl rs) {
462                this.owner = rs;
463        }
464
465        /*
466         * (non-Javadoc)
467         *
468         * @see com.mysql.jdbc.RowProvider#getOwner()
469         */
470        public ResultSetInternalMethods getOwner() {
471                return this.owner;
472        }
473
474        public boolean wasEmpty() {
475                return this.wasEmpty;
476        }
477       
478        public void setMetadata(Field[] metadata) {
479                this.metadata = metadata;
480        }
481
482}
Note: See TracBrowser for help on using the repository browser.