KickJava   Java API By Example, From Geeks To Geeks.

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


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

10 package com.ziclix.python.sql;
11
12 import com.ziclix.python.sql.util.PyArgParser;
13 import org.python.core.ClassDictInit;
14 import org.python.core.Py;
15 import org.python.core.PyBuiltinFunctionSet;
16 import org.python.core.PyClass;
17 import org.python.core.PyDictionary;
18 import org.python.core.PyException;
19 import org.python.core.PyInteger;
20 import org.python.core.PyList;
21 import org.python.core.PyObject;
22 import org.python.core.PyString;
23 import org.python.core.PyTuple;
24
25 import java.sql.DatabaseMetaData JavaDoc;
26 import java.sql.SQLException JavaDoc;
27 import java.sql.SQLWarning JavaDoc;
28 import java.sql.Statement JavaDoc;
29 import java.util.List JavaDoc;
30
31 /**
32  * These objects represent a database cursor, which is used to manage the
33  * context of a fetch operation.
34  *
35  * @author brian zimmer
36  * @author last revised by $Author: fwierzbicki $
37  * @version $Revision: 1.36 $
38  */

39 public class PyCursor extends PyObject implements ClassDictInit, WarningListener {
40
41   /** Field fetch */
42   protected Fetch fetch;
43
44   /** Field closed */
45   private boolean closed;
46
47   /** Field arraysize */
48   protected int arraysize;
49
50   /** Field softspace */
51   protected int softspace;
52
53   /** Field rsType */
54   protected PyObject rsType;
55
56   /** Field rsConcur */
57   protected PyObject rsConcur;
58
59   /** Field warnings */
60   protected PyObject warnings;
61
62   /** Field warnings */
63   protected PyObject lastrowid;
64
65   /** Field updatecount */
66   protected PyObject updatecount;
67
68   /** Field dynamicFetch */
69   protected boolean dynamicFetch;
70
71   /** Field connection */
72   protected PyConnection connection;
73
74   /** Field datahandler */
75   protected DataHandler datahandler;
76
77   /** Field statement */
78   protected PyStatement statement;
79
80   // they are stateless instances, so we only need to instantiate it once
81
private static final DataHandler DATAHANDLER = DataHandler.getSystemDataHandler();
82
83   /**
84    * Create the cursor with a static fetch.
85    *
86    * @param connection
87    */

88   PyCursor(PyConnection connection) {
89     this(connection, false);
90   }
91
92   /**
93    * Create the cursor, optionally choosing the type of fetch (static or dynamic).
94    * If dynamicFetch is true, then use a dynamic fetch.
95    *
96    * @param connection
97    * @param dynamicFetch
98    */

99   PyCursor(PyConnection connection, boolean dynamicFetch) {
100
101     this.arraysize = 1;
102     this.softspace = 0;
103     this.closed = false;
104     this.rsType = Py.None;
105     this.rsConcur = Py.None;
106     this.connection = connection;
107     this.datahandler = DATAHANDLER;
108     this.dynamicFetch = dynamicFetch;
109
110     // constructs the appropriate Fetch among other things
111
this.clear();
112   }
113
114   /**
115    * Create the cursor, optionally choosing the type of fetch (static or dynamic).
116    * If dynamicFetch is true, then use a dynamic fetch.
117    * rsType and rsConcur are used to create the Statement if both are non-None
118    *
119    * @param connection
120    * @param dynamicFetch
121    * @param rsType
122    * @param rsConcur
123    */

124   PyCursor(PyConnection connection, boolean dynamicFetch, PyObject rsType, PyObject rsConcur) {
125
126     this(connection, dynamicFetch);
127
128     this.rsType = rsType;
129     this.rsConcur = rsConcur;
130   }
131
132   /** Field __class__ */
133   public static PyClass __class__;
134
135   /**
136    * Method getPyClass
137    *
138    * @return PyClass
139    *
140    */

141   protected PyClass getPyClass() {
142     return __class__;
143   }
144
145   /** Field __methods__ */
146   protected static PyList __methods__;
147
148   /** Field __members__ */
149   protected static PyList __members__;
150
151   static {
152     PyObject[] m = new PyObject[9];
153
154     m[0] = new PyString("close");
155     m[1] = new PyString("execute");
156     m[2] = new PyString("executemany");
157     m[3] = new PyString("fetchone");
158     m[4] = new PyString("fetchall");
159     m[5] = new PyString("fetchmany");
160     m[6] = new PyString("callproc");
161     m[7] = new PyString("next");
162     m[8] = new PyString("write");
163     __methods__ = new PyList(m);
164     m = new PyObject[11];
165     m[0] = new PyString("arraysize");
166     m[1] = new PyString("rowcount");
167     m[2] = new PyString("rownumber");
168     m[3] = new PyString("description");
169     m[4] = new PyString("datahandler");
170     m[5] = new PyString("warnings");
171     m[6] = new PyString("lastrowid");
172     m[7] = new PyString("updatecount");
173     m[8] = new PyString("softspace");
174     m[9] = new PyString("closed");
175     m[10] = new PyString("connection");
176     __members__ = new PyList(m);
177   }
178
179   /**
180    * String representation of the object.
181    *
182    * @return a string representation of the object.
183    */

184   public String JavaDoc toString() {
185     return "<PyCursor object instance at " + Py.id(this) + ">";
186   }
187
188   /**
189    * Sets the attribute name to value.
190    *
191    * @param name
192    * @param value
193    */

194   public void __setattr__(String JavaDoc name, PyObject value) {
195
196     if ("arraysize".equals(name)) {
197       this.arraysize = ((PyInteger)value.__int__()).getValue();
198     } else if ("softspace".equals(name)) {
199       this.softspace = ((PyInteger)value.__int__()).getValue();
200     } else if ("datahandler".equals(name)) {
201       this.datahandler = (DataHandler)value.__tojava__(DataHandler.class);
202     } else {
203       super.__setattr__(name, value);
204     }
205   }
206
207   /**
208    * Gets the value of the attribute name.
209    *
210    * @param name
211    * @return the attribute for the given name
212    */

213   public PyObject __findattr__(String JavaDoc name) {
214
215     if ("arraysize".equals(name)) {
216       return Py.newInteger(arraysize);
217     } else if ("softspace".equals(name)) {
218       return Py.newInteger(softspace);
219     } else if ("__methods__".equals(name)) {
220       return __methods__;
221     } else if ("__members__".equals(name)) {
222       return __members__;
223     } else if ("description".equals(name)) {
224       return this.fetch.description;
225     } else if ("rowcount".equals(name)) {
226       return Py.newInteger(this.fetch.rowcount);
227     } else if ("rownumber".equals(name)) {
228       int rn = this.fetch.rownumber;
229       return (rn < 0) ? Py.None : Py.newInteger(rn);
230     } else if ("warnings".equals(name)) {
231       return warnings;
232     } else if ("lastrowid".equals(name)) {
233       return lastrowid;
234     } else if ("updatecount".equals(name)) {
235       return updatecount;
236     } else if ("datahandler".equals(name)) {
237       return Py.java2py(this.datahandler);
238     } else if ("dynamic".equals(name)) {
239       return this.dynamicFetch ? Py.One : Py.Zero;
240     } else if ("connection".equals(name)) {
241       return this.connection;
242     } else if ("closed".equals(name)) {
243       return Py.newBoolean(closed);
244     } else if ("callproc".equals(name)) {
245       try {
246         // dynamically decide on the the attribute based on the driver
247
if (!getMetaData().supportsStoredProcedures()) {
248             return null;
249         }
250       } catch (Throwable JavaDoc t) {}
251     }
252
253     return super.__findattr__(name);
254   }
255
256   /**
257    * Initializes the object's namespace.
258    *
259    * @param dict
260    */

261   static public void classDictInit(PyObject dict) {
262
263     dict.__setitem__("__version__", Py.newString("$Revision: 1.36 $").__getslice__(Py.newInteger(11), Py.newInteger(-2), null));
264     dict.__setitem__("fetchmany", new CursorFunc("fetchmany", 0, 0, 1, "fetch specified number of rows"));
265     dict.__setitem__("close", new CursorFunc("close", 1, 0, "close the cursor"));
266     dict.__setitem__("fetchall", new CursorFunc("fetchall", 2, 0, "fetch all results"));
267     dict.__setitem__("fetchone", new CursorFunc("fetchone", 3, 0, "fetch the next result"));
268     dict.__setitem__("nextset", new CursorFunc("nextset", 4, 0, "return next set or None"));
269     dict.__setitem__("execute", new CursorFunc("execute", 5, 1, 4, "execute the sql expression"));
270     dict.__setitem__("setinputsizes", new CursorFunc("setinputsizes", 6, 1, "not implemented"));
271     dict.__setitem__("setoutputsize", new CursorFunc("setoutputsize", 7, 1, 2, "not implemented"));
272     dict.__setitem__("callproc", new CursorFunc("callproc", 8, 1, 4, "executes a stored procedure"));
273     dict.__setitem__("executemany", new CursorFunc("executemany", 9, 1, 3, "execute sql with the parameter list"));
274     dict.__setitem__("scroll", new CursorFunc("scroll", 10, 1, 2, "scroll the cursor in the result set to a new position according to mode"));
275     dict.__setitem__("write", new CursorFunc("write", 11, 1, "execute the sql written to this file-like object"));
276     dict.__setitem__("prepare", new CursorFunc("prepare", 12, 1, "prepare the sql statement for later execution"));
277
278     // hide from python
279
dict.__setitem__("classDictInit", null);
280     dict.__setitem__("toString", null);
281     dict.__setitem__("getDataHandler", null);
282     dict.__setitem__("warning", null);
283     dict.__setitem__("fetch", null);
284     dict.__setitem__("statement", null);
285     dict.__setitem__("dynamicFetch", null);
286     dict.__setitem__("getPyClass", null);
287     dict.__setitem__("rsConcur", null);
288     dict.__setitem__("rsType", null);
289   }
290
291   /**
292    * Delete the cursor.
293    *
294    */

295   public void __del__() {
296     close();
297   }
298
299   /**
300    * Close the cursor now (rather than whenever __del__ is called).
301    * The cursor will be unusable from this point forward; an Error
302    * (or subclass) exception will be raised if any operation is
303    * attempted with the cursor.
304    *
305    */

306   public void close() {
307
308     try {
309       this.clear();
310       this.connection.remove(this);
311     } finally {
312       this.closed = true;
313     }
314   }
315
316   /**
317    * Returns an iteratable object.
318    *
319    * @return PyObject
320    *
321    * @since Jython 2.2, DB API 2.0+
322    */

323   public PyObject __iter__() {
324     return this;
325   }
326
327   /**
328    * Returns the next row from the currently executing SQL statement
329    * using the same semantics as .fetchone(). A StopIteration
330    * exception is raised when the result set is exhausted for Python
331    * versions 2.2 and later.
332    *
333    * @return PyObject
334    *
335    * @since Jython 2.2, DB API 2.0+
336    */

337   public PyObject next() {
338     PyObject row = __iternext__();
339     if (row == null) {
340       throw Py.StopIteration("");
341     }
342     return row;
343   }
344
345   /**
346    * Return the next element of the sequence that this is an iterator
347    * for. Returns null when the end of the sequence is reached.
348    *
349    * @since Jython 2.2
350    *
351    * @return PyObject
352    */

353   public PyObject __iternext__() {
354     PyObject row = fetchone();
355     return row.__nonzero__() ? row : null;
356   }
357
358   /**
359    * Return ths DatabaseMetaData for the current connection.
360    *
361    * @return DatabaseMetaData
362    *
363    * @throws SQLException
364    */

365   protected DatabaseMetaData JavaDoc getMetaData() throws SQLException JavaDoc {
366     return this.connection.connection.getMetaData();
367   }
368
369   /**
370    * Return the currently bound DataHandler.
371    *
372    * @return DataHandler
373    */

374   public DataHandler getDataHandler() {
375     return this.datahandler;
376   }
377
378   /**
379    * Prepare a statement ready for executing.
380    *
381    * @param sql the sql to execute or a prepared statement
382    * @param maxRows max number of rows to be returned
383    * @param prepared if true, prepare the statement, otherwise create a normal statement
384    *
385    * @return PyStatement
386    */

387   private PyStatement prepareStatement(PyObject sql, PyObject maxRows, boolean prepared) {
388
389     PyStatement stmt = null;
390
391     if (sql == Py.None) {
392       return null;
393     }
394
395     try {
396       if (sql instanceof PyStatement) {
397         stmt = (PyStatement)sql;
398       } else {
399         Statement JavaDoc sqlStatement = null;
400         String JavaDoc sqlString = sql.__str__().toString();
401
402         if (sqlString.trim().length() == 0) {
403           return null;
404         }
405
406         boolean normal = ((this.rsType == Py.None) && (this.rsConcur == Py.None));
407
408         if (normal) {
409           if (prepared) {
410             sqlStatement = this.connection.connection.prepareStatement(sqlString);
411           } else {
412             sqlStatement = this.connection.connection.createStatement();
413           }
414         } else {
415           int t = ((PyInteger)this.rsType.__int__()).getValue();
416           int c = ((PyInteger)this.rsConcur.__int__()).getValue();
417
418           if (prepared) {
419             sqlStatement = this.connection.connection.prepareStatement(sqlString, t, c);
420           } else {
421             sqlStatement = this.connection.connection.createStatement(t, c);
422           }
423         }
424
425         int style = prepared ? PyStatement.STATEMENT_PREPARED : PyStatement.STATEMENT_STATIC;
426
427         stmt = new PyStatement(sqlStatement, sqlString, style);
428       }
429
430       if (maxRows != Py.None) {
431         stmt.statement.setMaxRows(((PyInteger)maxRows.__int__()).getValue());
432       }
433     } catch (AbstractMethodError JavaDoc e) {
434       throw zxJDBC.makeException(zxJDBC.NotSupportedError, zxJDBC.getString("nodynamiccursors"));
435     } catch (PyException e) {
436       throw e;
437     } catch (Throwable JavaDoc e) {
438       throw zxJDBC.makeException(e);
439     }
440
441     return stmt;
442   }
443
444   /**
445    * This method is optional since not all databases provide stored procedures.
446    *
447    * Call a stored database procedure with the given name. The sequence of parameters
448    * must contain one entry for each argument that the procedure expects. The result of
449    * the call is returned as modified copy of the input sequence. Input parameters are
450    * left untouched, output and input/output parameters replaced with possibly new values.
451    *
452    * The procedure may also provide a result set as output. This must then be made available
453    * through the standard fetchXXX() methods.
454    *
455    * @param name
456    * @param params
457    * @param bindings
458    * @param maxRows
459    */

460   public void callproc(PyObject name, final PyObject params, PyObject bindings, PyObject maxRows) {
461
462     this.clear();
463
464     try {
465       if (getMetaData().supportsStoredProcedures()) {
466         if (isSeqSeq(params)) {
467           throw zxJDBC.makeException(zxJDBC.NotSupportedError, "sequence of sequences is not supported");
468         }
469
470         final Procedure procedure = datahandler.getProcedure(this, name);
471         Statement JavaDoc stmt = procedure.prepareCall(this.rsType, this.rsConcur);
472
473         if (maxRows != Py.None) {
474           stmt.setMaxRows(((PyInteger)maxRows.__int__()).getValue());
475         }
476
477         // get the bindings per the stored proc spec
478
PyDictionary callableBindings = new PyDictionary();
479
480         procedure.normalizeInput(params, callableBindings);
481
482         // overwrite with any user specific bindings
483
if (bindings instanceof PyDictionary) {
484           callableBindings.update((PyDictionary)bindings);
485         }
486
487         this.statement = new PyStatement(stmt, procedure);
488
489         this.execute(params, callableBindings);
490       } else {
491         throw zxJDBC.makeException(zxJDBC.NotSupportedError, zxJDBC.getString("noStoredProc"));
492       }
493     } catch (PyException e) {
494       throw e;
495     } catch (Throwable JavaDoc e) {
496       throw zxJDBC.makeException(e);
497     } finally {
498       if (this.statement != null) {
499
500         // close what we opened
501
this.statement.close();
502       }
503     }
504   }
505
506   /**
507    * Prepare a database operation (query or command) and then execute it against all
508    * parameter sequences or mappings found in the sequence seq_of_parameters.
509    * Modules are free to implement this method using multiple calls to the execute()
510    * method or by using array operations to have the database process the sequence as
511    * a whole in one call.
512    *
513    * The same comments as for execute() also apply accordingly to this method.
514    *
515    * Return values are not defined.
516    *
517    * @param sql
518    * @param params
519    * @param bindings
520    * @param maxRows
521    */

522   public void executemany(PyObject sql, PyObject params, PyObject bindings, PyObject maxRows) {
523     execute(sql, params, bindings, maxRows);
524   }
525
526   /**
527    * Prepare and execute a database operation (query or command).
528    * Parameters may be provided as sequence or mapping and will
529    * be bound to variables in the operation. Variables are specified
530    * in a database-specific notation (see the module's paramstyle
531    * attribute for details).
532    *
533    * A reference to the operation will be retained by the cursor.
534    * If the same operation object is passed in again, then the cursor
535    * can optimize its behavior. This is most effective for algorithms
536    * where the same operation is used, but different parameters are
537    * bound to it (many times).
538    *
539    * For maximum efficiency when reusing an operation, it is best to
540    * use the setinputsizes() method to specify the parameter types and
541    * sizes ahead of time. It is legal for a parameter to not match the
542    * predefined information; the implementation should compensate, possibly
543    * with a loss of efficiency.
544    *
545    * The parameters may also be specified as list of tuples to e.g. insert
546    * multiple rows in a single operation, but this kind of usage is
547    * deprecated: executemany() should be used instead.
548    *
549    * Return values are not defined.
550    *
551    * @param sql sql string or prepared statement
552    * @param params params for a prepared statement
553    * @param bindings dictionary of (param index : SQLType binding)
554    * @param maxRows integer value of max rows
555    */

556   public void execute(final PyObject sql, PyObject params, PyObject bindings, PyObject maxRows) {
557
558     this.clear();
559
560     boolean hasParams = hasParams(params);
561     PyStatement stmt = this.prepareStatement(sql, maxRows, hasParams);
562
563     if (stmt == null) {
564       return;
565     }
566
567     this.statement = stmt;
568
569     try {
570       synchronized (this.statement) {
571         if (hasParams) {
572
573           // if we have a sequence of sequences, let's run through them and finish
574
if (isSeqSeq(params)) {
575
576             // [(3, 4)] or [(3, 4), (5, 6)]
577
for (int i = 0, len = params.__len__(); i < len; i++) {
578               PyObject param = params.__getitem__(i);
579
580               this.execute(param, bindings);
581             }
582           } else {
583             this.execute(params, bindings);
584           }
585         } else {
586
587           // execute the sql string straight up
588
this.execute(Py.None, Py.None);
589         }
590       }
591     } catch (PyException e) {
592       throw e;
593     } catch (Throwable JavaDoc e) {
594       throw zxJDBC.makeException(e);
595     } finally {
596       if (this.statement != null) {
597
598         // only close static, single-use statements
599
if (!(sql instanceof PyStatement) && (!this.dynamicFetch)) {
600           this.statement.close();
601         }
602       }
603     }
604   }
605
606   /**
607    * Execute the current sql statement. Some generic functionality such
608    * as updating the lastrowid and updatecount occur as well.
609    */

610   protected void execute(PyObject params, PyObject bindings) {
611
612     try {
613       Statement JavaDoc stmt = this.statement.statement;
614
615       this.datahandler.preExecute(stmt);
616
617       // this performs the SQL execution and fetch per the Statement type
618
this.statement.execute(this, params, bindings);
619
620       this.lastrowid = this.datahandler.getRowId(stmt);
621
622       int uc = stmt.getUpdateCount();
623
624       this.updatecount = (uc < 0) ? Py.None : Py.newInteger(uc);
625
626       warning(new WarningEvent(this, stmt.getWarnings()));
627       this.datahandler.postExecute(stmt);
628     } catch (PyException e) {
629       throw e;
630     } catch (Throwable JavaDoc e) {
631       throw zxJDBC.makeException(e);
632     }
633   }
634
635   /**
636    * Fetch the next row of a query result set, returning a single sequence,
637    * or None when no more data is available.
638    *
639    * An Error (or subclass) exception is raised if the previous call to
640    * executeXXX() did not produce any result set or no call was issued yet.
641    *
642    * @return a single sequence from the result set, or None when no more data is available
643    */

644   public PyObject fetchone() {
645     return this.fetch.fetchone();
646   }
647
648   /**
649    * Fetch all (remaining) rows of a query result, returning them as a sequence
650    * of sequences (e.g. a list of tuples). Note that the cursor's arraysize attribute
651    * can affect the performance of this operation.
652    *
653    * An Error (or subclass) exception is raised if the previous call to executeXXX()
654    * did not produce any result set or no call was issued yet.
655    *
656    * @return a sequence of sequences from the result set, or an empty sequence when
657    * no more data is available
658    */

659   public PyObject fetchall() {
660     return this.fetch.fetchall();
661   }
662
663   /**
664    * Fetch the next set of rows of a query result, returning a sequence of
665    * sequences (e.g. a list of tuples). An empty sequence is returned when
666    * no more rows are available.
667    *
668    * The number of rows to fetch per call is specified by the parameter. If
669    * it is not given, the cursor's arraysize determines the number of rows
670    * to be fetched. The method should try to fetch as many rows as indicated
671    * by the size parameter. If this is not possible due to the specified number
672    * of rows not being available, fewer rows may be returned.
673    *
674    * An Error (or subclass) exception is raised if the previous call to executeXXX()
675    * did not produce any result set or no call was issued yet.
676    *
677    * Note there are performance considerations involved with the size parameter.
678    * For optimal performance, it is usually best to use the arraysize attribute.
679    * If the size parameter is used, then it is best for it to retain the same value
680    * from one fetchmany() call to the next.
681    *
682    * @param size
683    * @return a sequence of sequences from the result set, or an empty sequence when
684    * no more data is available
685    */

686   public PyObject fetchmany(int size) {
687     return this.fetch.fetchmany(size);
688   }
689
690   /**
691    * Move the result pointer to the next set if available.
692    *
693    * @return true if more sets exist, else None
694    */

695   public PyObject nextset() {
696     return this.fetch.nextset();
697   }
698
699   /**
700    * Prepare a sql statement for later execution.
701    *
702    * @param sql The sql string to be prepared.
703    *
704    * @return A prepared statement usable with .executeXXX()
705    */

706   public PyStatement prepare(PyObject sql) {
707
708     PyStatement s = this.prepareStatement(sql, Py.None, true);
709
710     // add to the set of statements which are leaving our control
711
this.connection.add(s);
712
713     return s;
714   }
715
716   /**
717    * Scroll the cursor in the result set to a new position according
718    * to mode.
719    *
720    * If mode is 'relative' (default), value is taken as offset to
721    * the current position in the result set, if set to 'absolute',
722    * value states an absolute target position.
723    *
724    * An IndexError should be raised in case a scroll operation would
725    * leave the result set. In this case, the cursor position is left
726    * undefined (ideal would be to not move the cursor at all).
727    *
728    * Note: This method should use native scrollable cursors, if
729    * available, or revert to an emulation for forward-only
730    * scrollable cursors. The method may raise NotSupportedErrors to
731    * signal that a specific operation is not supported by the
732    * database (e.g. backward scrolling).
733    *
734    *
735    * @param value
736    * @param mode
737    *
738    */

739   public void scroll(int value, String JavaDoc mode) {
740     this.fetch.scroll(value, mode);
741   }
742
743   /**
744    * Adds a warning to the tuple and will follow the chain as necessary.
745    *
746    * @param event
747    */

748   public void warning(WarningEvent event) {
749
750     if (this.warnings == Py.None) {
751       this.warnings = new PyList();
752     }
753
754     SQLWarning JavaDoc warning = event.getWarning();
755     while(warning != null) {
756
757       PyObject[] warn = new PyObject[] {
758         // there are three parts: (reason, state, vendorCode)
759
Py.java2py(warning.getMessage()),
760         Py.java2py(warning.getSQLState()),
761         Py.newInteger(warning.getErrorCode())
762       };
763
764       // add the warning to the list
765
((PyList)this.warnings).append(new PyTuple(warn));
766
767       warning = warning.getNextWarning();
768     }
769   }
770
771   /**
772    * Resets the cursor state. This includes flushing the warnings
773    * and any previous results.
774    *
775    */

776   protected void clear() {
777
778     if (closed) {
779       throw zxJDBC.makeException(zxJDBC.ProgrammingError, "cursor is closed");
780     }
781
782     this.warnings = Py.None;
783     this.lastrowid = Py.None;
784     this.updatecount = Py.newInteger(-1);
785
786     try {
787       this.fetch.close();
788     } catch (Throwable JavaDoc e) {}
789     finally {
790       this.fetch = Fetch.newFetch(this.datahandler, this.dynamicFetch);
791
792       this.fetch.addWarningListener(this);
793     }
794
795     if (this.statement != null) {
796
797       // we can't close a dynamic fetch statement until everything has been
798
// consumed so the only time we can clean up is now
799
// but if this is a previously prepared statement we don't want to close
800
// it underneath someone; we can check this by looking in the set
801
try {
802         if (this.dynamicFetch && (!this.connection.contains(this.statement))) {
803           this.statement.close();
804         }
805       } finally {
806         this.statement = null;
807       }
808     }
809   }
810
811   /**
812    * Method isSeq
813    *
814    * @param object
815    *
816    * @return true for any PyList, PyTuple or java.util.List
817    *
818    */

819   public static boolean isSeq(PyObject object) {
820
821     if ((object == null) || (object == Py.None)) {
822       return false;
823     }
824
825     if (object.__tojava__(List.class) != Py.NoConversion) {
826       return true;
827     }
828
829     // originally checked for __getitem__ and __len__, but this is true for PyString
830
// and we don't want to insert one character at a time
831
return (object instanceof PyList) || (object instanceof PyTuple);
832   }
833
834   /**
835    * Method hasParams
836    *
837    * @param params
838    *
839    * @return boolean
840    *
841    */

842   public static boolean hasParams(PyObject params) {
843     if(Py.None == params) {
844       return false;
845     }
846
847     boolean isSeq = isSeq(params);
848     // the optional argument better be a sequence
849
if (!isSeq) {
850       throw zxJDBC.makeException(zxJDBC.ProgrammingError, zxJDBC.getString("optionalSecond"));
851     }
852     return params.__len__() > 0;
853   }
854
855   /**
856    * Method isSeqSeq
857    *
858    * @param object
859    *
860    * @return true is a sequence of sequences
861    *
862    */

863   public static boolean isSeqSeq(PyObject object) {
864
865     if (isSeq(object) && (object.__len__() > 0)) {
866       for (int i = 0; i < object.__len__(); i++) {
867         if (!isSeq(object.__finditem__(i))) {
868           return false;
869         }
870       }
871       return true;
872     }
873     return false;
874   }
875 }
876
877 class CursorFunc extends PyBuiltinFunctionSet {
878   CursorFunc(String JavaDoc name, int index, int argcount, String JavaDoc doc) {
879     super(name, index, argcount, argcount, true, doc);
880   }
881   CursorFunc(String JavaDoc name, int index, int minargs, int maxargs, String JavaDoc doc) {
882     super(name, index, minargs, maxargs, true, doc);
883   }
884
885   public PyObject __call__() {
886     PyCursor cursor = (PyCursor)__self__;
887     switch (index) {
888       case 0 :
889         return cursor.fetchmany(cursor.arraysize);
890       case 1 :
891         cursor.close();
892         return Py.None;
893       case 2 :
894         return cursor.fetchall();
895       case 3 :
896         return cursor.fetchone();
897       case 4 :
898         return cursor.nextset();
899       default :
900         throw argCountError(0);
901     }
902   }
903
904   public PyObject __call__(PyObject arg) {
905     PyCursor cursor = (PyCursor)__self__;
906     switch (index) {
907       case 0 :
908         return cursor.fetchmany(((PyInteger)arg.__int__()).getValue());
909       case 5 :
910         cursor.execute(arg, Py.None, Py.None, Py.None);
911         return Py.None;
912       case 6 :
913       case 7 :
914         return Py.None;
915       case 8 :
916         cursor.callproc(arg, Py.None, Py.None, Py.None);
917         return Py.None;
918       case 9 :
919         cursor.executemany(arg, Py.None, Py.None, Py.None);
920         return Py.None;
921       case 10 :
922         cursor.scroll(((PyInteger)arg.__int__()).getValue(), "relative");
923         return Py.None;
924       case 11 :
925         cursor.execute(arg, Py.None, Py.None, Py.None);
926         return Py.None;
927       case 12 :
928         return cursor.prepare(arg);
929       default :
930         throw argCountError(1);
931     }
932   }
933
934   public PyObject __call__(PyObject arga, PyObject argb) {
935     PyCursor cursor = (PyCursor)__self__;
936     switch (index) {
937       case 5 :
938         cursor.execute(arga, argb, Py.None, Py.None);
939         return Py.None;
940       case 7 :
941         return Py.None;
942       case 8 :
943         cursor.callproc(arga, argb, Py.None, Py.None);
944         return Py.None;
945       case 9 :
946         cursor.executemany(arga, argb, Py.None, Py.None);
947         return Py.None;
948       case 10 :
949         cursor.scroll(((PyInteger)arga.__int__()).getValue(), argb.toString());
950         return Py.None;
951       default :
952         throw argCountError(2);
953     }
954   }
955
956   public PyObject __call__(PyObject arga, PyObject argb, PyObject argc) {
957     PyCursor cursor = (PyCursor)__self__;
958     switch (index) {
959       case 5 :
960         cursor.execute(arga, argb, argc, Py.None);
961         return Py.None;
962       case 8 :
963         cursor.callproc(arga, argb, argc, Py.None);
964         return Py.None;
965       case 9 :
966         cursor.executemany(arga, argb, argc, Py.None);
967         return Py.None;
968       default :
969         throw argCountError(3);
970     }
971   }
972
973   public PyObject __call__(PyObject[] args, String JavaDoc[] keywords) {
974
975     PyCursor cursor = (PyCursor)__self__;
976     PyArgParser parser = new PyArgParser(args, keywords);
977     PyObject sql = parser.arg(0);
978     PyObject params = parser.kw("params", Py.None);
979     PyObject bindings = parser.kw("bindings", Py.None);
980     PyObject maxrows = parser.kw("maxrows", Py.None);
981
982     params = (parser.numArg() >= 2) ? parser.arg(1) : params;
983     bindings = (parser.numArg() >= 3) ? parser.arg(2) : bindings;
984     maxrows = (parser.numArg() >= 4) ? parser.arg(3) : maxrows;
985
986     switch (index) {
987       case 5 :
988         cursor.execute(sql, params, bindings, maxrows);
989         return Py.None;
990       case 8 :
991         cursor.callproc(sql, params, bindings, maxrows);
992         return Py.None;
993       case 9 :
994         cursor.executemany(sql, params, bindings, maxrows);
995         return Py.None;
996       default :
997         throw argCountError(args.length);
998     }
999   }
1000}
1001
Popular Tags