KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > ziclix > python > sql > Fetch


1 /*
2  * Jython Database Specification API 2.0
3  *
4  * $Id: Fetch.java,v 1.18 2005/06/20 17:12:12 fwierzbicki Exp $
5  *
6  * Copyright (c) 2001 brian zimmer <bzimmer@ziclix.com>
7  *
8  */

9 package com.ziclix.python.sql;
10
11 import org.python.core.Py;
12 import org.python.core.PyException;
13 import org.python.core.PyInteger;
14 import org.python.core.PyList;
15 import org.python.core.PyObject;
16 import org.python.core.PyTuple;
17 import org.python.core.__builtin__;
18
19 import java.sql.CallableStatement JavaDoc;
20 import java.sql.DatabaseMetaData JavaDoc;
21 import java.sql.ResultSet JavaDoc;
22 import java.sql.ResultSetMetaData JavaDoc;
23 import java.sql.SQLException JavaDoc;
24 import java.sql.SQLWarning JavaDoc;
25 import java.sql.Types JavaDoc;
26 import java.util.ArrayList JavaDoc;
27 import java.util.LinkedList JavaDoc;
28 import java.util.List JavaDoc;
29 import java.util.Set JavaDoc;
30
31 /**
32  * <p>The responsibility of a Fetch instance is to manage the iteration of a
33  * ResultSet. Two different alogorithms are available: static or dynamic.</p>
34  * <p/>
35  * <p><b>Static</b> The static variety iterates the entire set immediately,
36  * creating the necessary Jython objects and storing them. It is able to
37  * immediately close the ResultSet so a call to close() is essentially a no-op
38  * from a database resource perspective (it does clear the results list however).
39  * This approach also allows for the correct rowcount to be determined since
40  * the entire result set has been iterated.</p>
41  * <p/>
42  * <p><b>Dynamic</b> The dynamic variety iterates the result set only as requested.
43  * This holds a bit truer to the intent of the API as the fetch*() methods actually
44  * fetch when instructed. This is especially useful for managing exeedingly large
45  * results, but is unable to determine the rowcount without having worked through
46  * the entire result set. The other disadvantage is the ResultSet remains open
47  * throughout the entire iteration. So the tradeoff is in open database resources
48  * versus JVM resources since the application can keep constant space if it doesn't
49  * require the entire result set be presented as one.</p>
50  *
51  * @author brian zimmer
52  * @version $Revision: 1.18 $
53  */

54 abstract public class Fetch {
55
56     /**
57      * The total number of rows in the result set.
58      * <p/>
59      * Note: since JDBC provides no means to get this information without iterating
60      * the entire result set, only those fetches which build the result statically
61      * will have an accurate row count.
62      */

63     protected int rowcount;
64
65     /**
66      * The current row of the cursor (-1 if off either end).
67      */

68     protected int rownumber;
69
70     /**
71      * Field cursor
72      */

73     private DataHandler datahandler;
74
75     /**
76      * Field description
77      */

78     protected PyObject description;
79
80     /**
81      * A list of warning listeners.
82      */

83     private List listeners;
84
85     /**
86      * Constructor Fetch
87      *
88      * @param datahandler
89      */

90     protected Fetch(DataHandler datahandler) {
91
92         this.rowcount = -1;
93         this.rownumber = -1;
94         this.description = Py.None;
95         this.datahandler = datahandler;
96         this.listeners = new ArrayList JavaDoc(3);
97     }
98
99     /**
100      * Method newFetch
101      *
102      * @param datahandler
103      * @param dynamic
104      * @return Fetch
105      */

106     public static Fetch newFetch(DataHandler datahandler, boolean dynamic) {
107
108         if (dynamic) {
109             return new DynamicFetch(datahandler);
110         } else {
111             return new StaticFetch(datahandler);
112         }
113     }
114
115     /**
116      * The number of rows in the current result set.
117      */

118     public int getRowCount() {
119         return this.rowcount;
120     }
121
122     /**
123      * The description of each column, in order, for the data in the result
124      * set.
125      */

126     public PyObject getDescription() {
127         return this.description;
128     }
129
130     /**
131      * Create the results after a successful execution and manages the result set.
132      *
133      * @param resultSet
134      */

135     abstract public void add(ResultSet JavaDoc resultSet);
136
137     /**
138      * Create the results after a successful execution and manages the result set.
139      * Optionally takes a set of JDBC-indexed columns to automatically set to None
140      * primarily to support getTypeInfo() which sets a column type of a number but
141      * doesn't use the value so a driver is free to put anything it wants there.
142      *
143      * @param resultSet
144      * @param skipCols JDBC-indexed set of columns to be skipped
145      */

146     abstract public void add(ResultSet JavaDoc resultSet, Set JavaDoc skipCols);
147
148     /**
149      * Method add
150      *
151      * @param callableStatement
152      * @param procedure
153      * @param params
154      */

155     abstract public void add(CallableStatement JavaDoc callableStatement, Procedure procedure, PyObject params);
156
157     /**
158      * Fetch the next row of a query result set, returning a single sequence,
159      * or None when no more data is available.
160      * <p/>
161      * An Error (or subclass) exception is raised if the previous call to
162      * executeXXX() did not produce any result set or no call was issued yet.
163      *
164      * @return a single sequence from the result set, or None when no more data is available
165      */

166     public PyObject fetchone() {
167
168         PyObject sequence = fetchmany(1);
169
170         if (sequence.__len__() == 1) {
171             return sequence.__getitem__(0);
172         } else {
173             return Py.None;
174         }
175     }
176
177     /**
178      * Fetch all (remaining) rows of a query result, returning them as a sequence
179      * of sequences (e.g. a list of tuples). Note that the cursor's arraysize attribute
180      * can affect the performance of this operation.
181      * <p/>
182      * An Error (or subclass) exception is raised if the previous call to executeXXX()
183      * did not produce any result set or no call was issued yet.
184      *
185      * @return a sequence of sequences from the result set, or None when no more data is available
186      */

187     public abstract PyObject fetchall();
188
189     /**
190      * Fetch the next set of rows of a query result, returning a sequence of
191      * sequences (e.g. a list of tuples). An empty sequence is returned when
192      * no more rows are available.
193      * <p/>
194      * The number of rows to fetch per call is specified by the parameter. If
195      * it is not given, the cursor's arraysize determines the number of rows
196      * to be fetched. The method should try to fetch as many rows as indicated
197      * by the size parameter. If this is not possible due to the specified number
198      * of rows not being available, fewer rows may be returned.
199      * <p/>
200      * An Error (or subclass) exception is raised if the previous call to executeXXX()
201      * did not produce any result set or no call was issued yet.
202      * <p/>
203      * Note there are performance considerations involved with the size parameter.
204      * For optimal performance, it is usually best to use the arraysize attribute.
205      * If the size parameter is used, then it is best for it to retain the same value
206      * from one fetchmany() call to the next.
207      *
208      * @return a sequence of sequences from the result set, or None when no more data is available
209      */

210     public abstract PyObject fetchmany(int size);
211
212     /**
213      * Move the result pointer to the next set if available.
214      *
215      * @return true if more sets exist, else None
216      */

217     public abstract PyObject nextset();
218
219     /**
220      * Scroll the cursor in the result set to a new position according
221      * to mode.
222      * <p/>
223      * If mode is 'relative' (default), value is taken as offset to
224      * the current position in the result set, if set to 'absolute',
225      * value states an absolute target position.
226      * <p/>
227      * An IndexError should be raised in case a scroll operation would
228      * leave the result set. In this case, the cursor position is left
229      * undefined (ideal would be to not move the cursor at all).
230      * <p/>
231      * Note: This method should use native scrollable cursors, if
232      * available, or revert to an emulation for forward-only
233      * scrollable cursors. The method may raise NotSupportedErrors to
234      * signal that a specific operation is not supported by the
235      * database (e.g. backward scrolling).
236      *
237      * @param value
238      * @param mode
239      */

240     public abstract void scroll(int value, String JavaDoc mode);
241
242     /**
243      * Cleanup any resources.
244      */

245     public void close() throws SQLException JavaDoc {
246         this.listeners.clear();
247     }
248
249     /**
250      * Builds a tuple containing the meta-information about each column.
251      * <p/>
252      * (name, type_code, display_size, internal_size, precision, scale, null_ok)
253      * <p/>
254      * precision and scale are only available for numeric types
255      */

256     protected PyObject createDescription(ResultSetMetaData JavaDoc meta) throws SQLException JavaDoc {
257
258         PyObject metadata = new PyList();
259
260         for (int i = 1; i <= meta.getColumnCount(); i++) {
261             PyObject[] a = new PyObject[7];
262
263             a[0] = Py.newString(meta.getColumnName(i));
264             a[1] = Py.newInteger(meta.getColumnType(i));
265             a[2] = Py.newInteger(meta.getColumnDisplaySize(i));
266             a[3] = Py.None;
267
268             switch (meta.getColumnType(i)) {
269
270                 case Types.BIGINT:
271                 case Types.BIT:
272                 case Types.DECIMAL:
273                 case Types.DOUBLE:
274                 case Types.FLOAT:
275                 case Types.INTEGER:
276                 case Types.SMALLINT:
277                     a[4] = Py.newInteger(meta.getPrecision(i));
278                     a[5] = Py.newInteger(meta.getScale(i));
279                     break;
280
281                 default :
282                     a[4] = Py.None;
283                     a[5] = Py.None;
284                     break;
285             }
286
287             a[6] = Py.newInteger(meta.isNullable(i));
288
289             ((PyList) metadata).append(new PyTuple(a));
290         }
291
292         return metadata;
293     }
294
295     /**
296      * Builds a tuple containing the meta-information about each column.
297      * <p/>
298      * (name, type_code, display_size, internal_size, precision, scale, null_ok)
299      * <p/>
300      * precision and scale are only available for numeric types
301      */

302     protected PyObject createDescription(Procedure procedure) throws SQLException JavaDoc {
303
304         PyObject metadata = new PyList();
305
306         for (int i = 0, len = procedure.columns.__len__(); i < len; i++) {
307             PyObject column = procedure.columns.__getitem__(i);
308             int colType = ((PyInteger)column.__getitem__(Procedure.COLUMN_TYPE).__int__()).getValue();
309
310             switch (colType) {
311
312                 case DatabaseMetaData.procedureColumnReturn:
313                     PyObject[] a = new PyObject[7];
314
315                     a[0] = column.__getitem__(Procedure.NAME);
316                     a[1] = column.__getitem__(Procedure.DATA_TYPE);
317                     a[2] = Py.newInteger(-1);
318                     a[3] = column.__getitem__(Procedure.LENGTH);
319
320                     switch (((PyInteger)a[1].__int__()).getValue()) {
321
322                         case Types.BIGINT:
323                         case Types.BIT:
324                         case Types.DECIMAL:
325                         case Types.DOUBLE:
326                         case Types.FLOAT:
327                         case Types.INTEGER:
328                         case Types.SMALLINT:
329                             a[4] = column.__getitem__(Procedure.PRECISION);
330                             a[5] = column.__getitem__(Procedure.SCALE);
331                             break;
332
333                         default :
334                             a[4] = Py.None;
335                             a[5] = Py.None;
336                             break;
337                     }
338
339                     int nullable = ((PyInteger)column.__getitem__(Procedure.NULLABLE).__int__()).getValue();
340
341                     a[6] = (nullable == DatabaseMetaData.procedureNullable) ? Py.One : Py.Zero;
342
343                     ((PyList) metadata).append(new PyTuple(a));
344                     break;
345             }
346         }
347
348         return metadata;
349     }
350
351     /**
352      * Method createResults
353      *
354      * @param callableStatement
355      * @param procedure
356      * @param params
357      * @return PyObject
358      * @throws SQLException
359      */

360     protected PyObject createResults(CallableStatement JavaDoc callableStatement, Procedure procedure, PyObject params) throws SQLException JavaDoc {
361
362         PyList results = new PyList();
363
364         for (int i = 0, j = 0, len = procedure.columns.__len__(); i < len; i++) {
365             PyObject obj = Py.None;
366             PyObject column = procedure.columns.__getitem__(i);
367             int colType = ((PyInteger)column.__getitem__(Procedure.COLUMN_TYPE).__int__()).getValue();
368             int dataType = ((PyInteger)column.__getitem__(Procedure.DATA_TYPE).__int__()).getValue();
369
370             switch (colType) {
371
372                 case DatabaseMetaData.procedureColumnIn:
373                     j++;
374                     break;
375
376                 case DatabaseMetaData.procedureColumnOut:
377                 case DatabaseMetaData.procedureColumnInOut:
378                     obj = datahandler.getPyObject(callableStatement, i + 1, dataType);
379
380                     params.__setitem__(j++, obj);
381                     break;
382
383                 case DatabaseMetaData.procedureColumnReturn:
384                     obj = datahandler.getPyObject(callableStatement, i + 1, dataType);
385
386                     // Oracle sends ResultSets as a return value
387
Object JavaDoc rs = obj.__tojava__(ResultSet JavaDoc.class);
388
389                     if (rs == Py.NoConversion) {
390                         results.append(obj);
391                     } else {
392                         add((ResultSet JavaDoc) rs);
393                     }
394                     break;
395             }
396         }
397
398         if (results.__len__() == 0) {
399             return results;
400         }
401
402         PyList ret = new PyList();
403
404         ret.append(__builtin__.tuple(results));
405
406         return ret;
407     }
408
409     /**
410      * Creates the results of a query. Iterates through the list and builds the tuple.
411      *
412      * @param set result set
413      * @param skipCols set of JDBC-indexed columns to automatically set to None
414      * @return a list of tuples of the results
415      * @throws SQLException
416      */

417     protected PyList createResults(ResultSet JavaDoc set, Set JavaDoc skipCols, PyObject metaData) throws SQLException JavaDoc {
418
419         PyList res = new PyList();
420
421         while (set.next()) {
422             PyObject tuple = createResult(set, skipCols, metaData);
423
424             res.append(tuple);
425         }
426
427         return res;
428     }
429
430     /**
431      * Creates the individual result row from the current ResultSet row.
432      *
433      * @param set result set
434      * @param skipCols set of JDBC-indexed columns to automatically set to None
435      * @return a tuple of the results
436      * @throws SQLException
437      */

438     protected PyTuple createResult(ResultSet JavaDoc set, Set JavaDoc skipCols, PyObject metaData) throws SQLException JavaDoc {
439
440         int descriptionLength = metaData.__len__();
441         PyObject[] row = new PyObject[descriptionLength];
442
443         for (int i = 0; i < descriptionLength; i++) {
444             if ((skipCols != null) && skipCols.contains(new Integer JavaDoc(i + 1))) {
445                 row[i] = Py.None;
446             } else {
447                 int type = ((PyInteger) metaData.__getitem__(i).__getitem__(1)).getValue();
448
449                 row[i] = datahandler.getPyObject(set, i + 1, type);
450             }
451         }
452
453         SQLWarning JavaDoc warning = set.getWarnings();
454
455         if (warning != null) {
456             fireWarning(warning);
457         }
458
459         PyTuple tuple = new PyTuple(row);
460
461         return tuple;
462     }
463
464     protected void fireWarning(SQLWarning JavaDoc warning) {
465
466         WarningEvent event = new WarningEvent(this, warning);
467
468         for (int i = listeners.size() - 1; i >= 0; i--) {
469             try {
470                 ((WarningListener) listeners.get(i)).warning(event);
471             } catch (Throwable JavaDoc t) {
472             }
473         }
474     }
475
476     public void addWarningListener(WarningListener listener) {
477         this.listeners.add(listener);
478     }
479
480     public boolean removeWarningListener(WarningListener listener) {
481         return this.listeners.remove(listener);
482     }
483 }
484
485 /**
486  * This version of fetch builds the results statically. This consumes more resources but
487  * allows for efficient closing of database resources because the contents of the result
488  * set are immediately consumed. It also allows for an accurate rowcount attribute, whereas
489  * a dynamic query is unable to provide this information until all the results have been
490  * consumed.
491  */

492 class StaticFetch extends Fetch {
493
494     /**
495      * Field results
496      */

497     protected List results;
498
499     /**
500      * Field descriptions
501      */

502     protected List descriptions;
503
504     /**
505      * Construct a static fetch. The entire result set is iterated as it
506      * is added and the result set is immediately closed.
507      */

508     public StaticFetch(DataHandler datahandler) {
509
510         super(datahandler);
511
512         this.results = new LinkedList JavaDoc();
513         this.descriptions = new LinkedList JavaDoc();
514     }
515
516     /**
517      * Method add
518      *
519      * @param resultSet
520      */

521     public void add(ResultSet JavaDoc resultSet) {
522         this.add(resultSet, null);
523     }
524
525     /**
526      * Method add
527      *
528      * @param resultSet
529      * @param skipCols
530      */

531     public void add(ResultSet JavaDoc resultSet, Set JavaDoc skipCols) {
532
533         try {
534             if ((resultSet != null) && (resultSet.getMetaData() != null)) {
535                 PyObject metadata = this.createDescription(resultSet.getMetaData());
536                 PyObject result = this.createResults(resultSet, skipCols, metadata);
537
538                 this.results.add(result);
539                 this.descriptions.add(metadata);
540
541                 // we want the rowcount of the first result set
542
this.rowcount = ((PyObject) this.results.get(0)).__len__();
543
544                 // we want the description of the first result set
545
this.description = ((PyObject) this.descriptions.get(0));
546
547                 // set the current rownumber
548
this.rownumber = 0;
549             }
550         } catch (PyException e) {
551             throw e;
552         } catch (Throwable JavaDoc e) {
553             throw zxJDBC.makeException(e);
554         } finally {
555             try {
556                 resultSet.close();
557             } catch (Throwable JavaDoc e) {
558             }
559         }
560     }
561
562     /**
563      * Method add
564      *
565      * @param callableStatement
566      * @param procedure
567      * @param params
568      */

569     public void add(CallableStatement JavaDoc callableStatement, Procedure procedure, PyObject params) {
570
571         try {
572             PyObject result = this.createResults(callableStatement, procedure, params);
573
574             if (result.__len__() > 0) {
575                 this.results.add(result);
576                 this.descriptions.add(this.createDescription(procedure));
577
578                 // we want the rowcount of the first result set
579
this.rowcount = ((PyObject) this.results.get(0)).__len__();
580
581                 // we want the description of the first result set
582
this.description = ((PyObject) this.descriptions.get(0));
583
584                 // set the current rownumber
585
this.rownumber = 0;
586             }
587         } catch (PyException e) {
588             throw e;
589         } catch (Throwable JavaDoc e) {
590             throw zxJDBC.makeException(e);
591         }
592     }
593
594     /**
595      * Fetch all (remaining) rows of a query result, returning them as a sequence
596      * of sequences (e.g. a list of tuples). Note that the cursor's arraysize attribute
597      * can affect the performance of this operation.
598      * <p/>
599      * An Error (or subclass) exception is raised if the previous call to executeXXX()
600      * did not produce any result set or no call was issued yet.
601      *
602      * @return a sequence of sequences from the result set, or an empty sequence when
603      * no more data is available
604      */

605     public PyObject fetchall() {
606         return fetchmany(this.rowcount);
607     }
608
609     /**
610      * Fetch the next set of rows of a query result, returning a sequence of
611      * sequences (e.g. a list of tuples). An empty sequence is returned when
612      * no more rows are available.
613      * <p/>
614      * The number of rows to fetch per call is specified by the parameter. If
615      * it is not given, the cursor's arraysize determines the number of rows
616      * to be fetched. The method should try to fetch as many rows as indicated
617      * by the size parameter. If this is not possible due to the specified number
618      * of rows not being available, fewer rows may be returned.
619      * <p/>
620      * An Error (or subclass) exception is raised if the previous call to executeXXX()
621      * did not produce any result set or no call was issued yet.
622      * <p/>
623      * Note there are performance considerations involved with the size parameter.
624      * For optimal performance, it is usually best to use the arraysize attribute.
625      * If the size parameter is used, then it is best for it to retain the same value
626      * from one fetchmany() call to the next.
627      *
628      * @return a sequence of sequences from the result set, or an empty sequence when
629      * no more data is available
630      */

631     public PyObject fetchmany(int size) {
632
633         if ((results == null) || (results.size() == 0)) {
634             throw zxJDBC.makeException(zxJDBC.DatabaseError, "no results");
635         }
636
637         PyObject res = new PyList();
638         PyObject current = (PyObject) results.get(0);
639
640         if (size <= 0) {
641             size = this.rowcount;
642         }
643
644         if (this.rownumber < this.rowcount) {
645             res = current.__getslice__(Py.newInteger(this.rownumber), Py.newInteger(this.rownumber + size), Py.One);
646             this.rownumber += size;
647         }
648
649         return res;
650     }
651
652     /**
653      * Method scroll
654      *
655      * @param value
656      * @param mode 'relative' or 'absolute'
657      */

658     public void scroll(int value, String JavaDoc mode) {
659
660         int pos;
661
662         if ("relative".equals(mode)) {
663             pos = this.rownumber + value;
664         } else if ("absolute".equals(mode)) {
665             pos = value;
666         } else {
667             throw zxJDBC.makeException(zxJDBC.ProgrammingError, "invalid cursor scroll mode [" + mode + "]");
668         }
669
670         if ((pos >= 0) && (pos < this.rowcount)) {
671             this.rownumber = pos;
672         } else {
673             throw zxJDBC.makeException(Py.IndexError, "cursor index [" + pos + "] out of range");
674         }
675     }
676
677     /**
678      * Move the result pointer to the next set if available.
679      *
680      * @return true if more sets exist, else None
681      */

682     public PyObject nextset() {
683
684         PyObject next = Py.None;
685
686         if ((results != null) && (results.size() > 1)) {
687             this.results.remove(0);
688             this.descriptions.remove(0);
689
690             next = (PyObject) this.results.get(0);
691             this.description = (PyObject) this.descriptions.get(0);
692             this.rowcount = next.__len__();
693             this.rownumber = 0;
694         }
695
696         return (next == Py.None) ? Py.None : Py.One;
697     }
698
699     /**
700      * Remove the results.
701      */

702     public void close() throws SQLException JavaDoc {
703
704         super.close();
705
706         this.rownumber = -1;
707
708         this.results.clear();
709     }
710 }
711
712 /**
713  * Dynamically construct the results from an execute*(). The static version builds the entire
714  * result set immediately upon completion of the query, however in some circumstances, this
715  * requires far too many resources to be efficient. In this version of the fetch the resources
716  * remain constant. The dis-advantage to this approach from an API perspective is its impossible
717  * to generate an accurate rowcount since not all the rows have been consumed.
718  */

719 class DynamicFetch extends Fetch {
720
721     /**
722      * Field skipCols
723      */

724     protected Set JavaDoc skipCols;
725
726     /**
727      * Field resultSet
728      */

729     protected ResultSet JavaDoc resultSet;
730
731     /**
732      * Construct a dynamic fetch.
733      */

734     public DynamicFetch(DataHandler datahandler) {
735         super(datahandler);
736     }
737
738     /**
739      * Add the result set to the results. If more than one result
740      * set is attempted to be added, an Error is raised since JDBC
741      * requires that only one ResultSet be iterated for one Statement
742      * at any one time. Since this is a dynamic iteration, it precludes
743      * the addition of more than one result set.
744      */

745     public void add(ResultSet JavaDoc resultSet) {
746         add(resultSet, null);
747     }
748
749     /**
750      * Add the result set to the results. If more than one result
751      * set is attempted to be added, an Error is raised since JDBC
752      * requires that only one ResultSet be iterated for one Statement
753      * at any one time. Since this is a dynamic iteration, it precludes
754      * the addition of more than one result set.
755      */

756     public void add(ResultSet JavaDoc resultSet, Set JavaDoc skipCols) {
757
758         if (this.resultSet != null) {
759             throw zxJDBC.makeException(zxJDBC.getString("onlyOneResultSet"));
760         }
761
762         try {
763             if ((resultSet != null) && (resultSet.getMetaData() != null)) {
764                 if (this.description == Py.None) {
765                     this.description = this.createDescription(resultSet.getMetaData());
766                 }
767
768                 this.resultSet = resultSet;
769                 this.skipCols = skipCols;
770
771                 // it would be more compliant if we knew the resultSet actually
772
// contained some rows, but since we don't make a stab at it so
773
// everything else looks better
774
this.rowcount = 0;
775                 this.rownumber = 0;
776             }
777         } catch (PyException e) {
778             throw e;
779         } catch (Throwable JavaDoc e) {
780             throw zxJDBC.makeException(e);
781         }
782     }
783
784     /**
785      * Method add
786      *
787      * @param callableStatement
788      * @param procedure
789      * @param params
790      */

791     public void add(CallableStatement JavaDoc callableStatement, Procedure procedure, PyObject params) {
792         throw zxJDBC.makeException(zxJDBC.NotSupportedError, zxJDBC.getString("nocallprocsupport"));
793     }
794
795     /**
796      * Iterate the remaining contents of the ResultSet and return.
797      */

798     public PyObject fetchall() {
799         return fetch(0, true);
800     }
801
802     /**
803      * Iterate up to size rows remaining in the ResultSet and return.
804      */

805     public PyObject fetchmany(int size) {
806         return fetch(size, false);
807     }
808
809     /**
810      * Internal use only. If <i>all</i> is true, return everything
811      * that's left in the result set, otherwise return up to size. Fewer
812      * than size may be returned if fewer than size results are left in
813      * the set.
814      */

815     private PyObject fetch(int size, boolean all) {
816
817         PyList res = new PyList();
818
819         if (this.resultSet == null) {
820             throw zxJDBC.makeException(zxJDBC.DatabaseError, "no results");
821         }
822
823         try {
824             all = (size < 0) ? true : all;
825
826             while (((size-- > 0) || all) && this.resultSet.next()) {
827                 PyTuple tuple = createResult(this.resultSet, this.skipCols, this.description);
828                 res.append(tuple);
829                 this.rowcount++;
830                 this.rownumber = this.resultSet.getRow();
831             }
832         } catch (AbstractMethodError JavaDoc e) {
833             throw zxJDBC.makeException(zxJDBC.NotSupportedError, zxJDBC.getString("nodynamiccursors"));
834         } catch (PyException e) {
835             throw e;
836         } catch (Throwable JavaDoc e) {
837             throw zxJDBC.makeException(e);
838         }
839
840         return res;
841     }
842
843     /**
844      * Always returns None.
845      */

846     public PyObject nextset() {
847         return Py.None;
848     }
849
850     /**
851      * Method scroll
852      *
853      * @param value
854      * @param mode
855      */

856     public void scroll(int value, String JavaDoc mode) {
857
858         try {
859             int type = this.resultSet.getType();
860
861             if ((type != ResultSet.TYPE_FORWARD_ONLY) || (value > 0)) {
862                 if ("relative".equals(mode)) {
863                     if (value < 0) {
864                         value = Math.abs(this.rownumber + value);
865                     } else if (value > 0) {
866                         value = this.rownumber + value + 1;
867                     }
868                 } else if ("absolute".equals(mode)) {
869                     if (value < 0) {
870                         throw zxJDBC.makeException(Py.IndexError, "cursor index [" + value + "] out of range");
871                     }
872                 } else {
873                     throw zxJDBC.makeException(zxJDBC.ProgrammingError, "invalid cursor scroll mode [" + mode + "]");
874                 }
875
876                 if (value == 0) {
877                     this.resultSet.beforeFirst();
878                 } else {
879                     if (!this.resultSet.absolute(value)) {
880                         throw zxJDBC.makeException(Py.IndexError, "cursor index [" + value + "] out of range");
881                     }
882                 }
883
884                 // since .rownumber is the *next* row, then the JDBC value suits us fine
885
this.rownumber = this.resultSet.getRow();
886             } else {
887                 String JavaDoc msg = "dynamic result set of type [" + type + "] does not support scrolling";
888
889                 throw zxJDBC.makeException(zxJDBC.NotSupportedError, msg);
890             }
891         } catch (AbstractMethodError JavaDoc e) {
892             throw zxJDBC.makeException(zxJDBC.NotSupportedError, zxJDBC.getString("nodynamiccursors"));
893         } catch (SQLException JavaDoc e) {
894             throw zxJDBC.makeException(e);
895         } catch (Throwable JavaDoc t) {
896             throw zxJDBC.makeException(t);
897         }
898     }
899
900     /**
901      * Close the underlying ResultSet.
902      */

903     public void close() throws SQLException JavaDoc {
904
905         super.close();
906
907         if (this.resultSet == null) {
908             return;
909         }
910
911         this.rownumber = -1;
912
913         try {
914             this.resultSet.close();
915         } finally {
916             this.resultSet = null;
917         }
918     }
919 }
920
Popular Tags