From: <pj...@us...> - 2009-07-21 00:56:50
|
Revision: 6552 http://jython.svn.sourceforge.net/jython/?rev=6552&view=rev Author: pjenvey Date: 2009-07-21 00:56:33 +0000 (Tue, 21 Jul 2009) Log Message: ----------- coding standards: 4 space indents, remove redundant parens, whitespace Modified Paths: -------------- trunk/jython/src/com/ziclix/python/sql/PyCursor.java Modified: trunk/jython/src/com/ziclix/python/sql/PyCursor.java =================================================================== --- trunk/jython/src/com/ziclix/python/sql/PyCursor.java 2009-07-20 17:35:01 UTC (rev 6551) +++ trunk/jython/src/com/ziclix/python/sql/PyCursor.java 2009-07-21 00:56:33 UTC (rev 6552) @@ -1,4 +1,3 @@ - /* * Jython Database Specification API 2.0 * @@ -14,6 +13,7 @@ import java.sql.SQLWarning; import java.sql.Statement; import java.util.List; + import org.python.core.ClassDictInit; import org.python.core.Py; import org.python.core.PyBuiltinMethodSet; @@ -23,6 +23,7 @@ import org.python.core.PyObject; import org.python.core.PyString; import org.python.core.PyTuple; + import com.ziclix.python.sql.util.PyArgParser; /** @@ -35,956 +36,957 @@ */ public class PyCursor extends PyObject implements ClassDictInit, WarningListener { - /** Field fetch */ - protected Fetch fetch; + /** Field fetch */ + protected Fetch fetch; - /** Field closed */ - private boolean closed; + /** Field closed */ + private boolean closed; - /** Field arraysize */ - protected int arraysize; + /** Field arraysize */ + protected int arraysize; - /** Field softspace */ - protected int softspace; + /** Field softspace */ + protected int softspace; - /** Field rsType */ - protected PyObject rsType; + /** Field rsType */ + protected PyObject rsType; - /** Field rsConcur */ - protected PyObject rsConcur; + /** Field rsConcur */ + protected PyObject rsConcur; - /** Field warnings */ - protected PyObject warnings; + /** Field warnings */ + protected PyObject warnings; - /** Field warnings */ - protected PyObject lastrowid; + /** Field warnings */ + protected PyObject lastrowid; - /** Field updatecount */ - protected PyObject updatecount; + /** Field updatecount */ + protected PyObject updatecount; - /** Field dynamicFetch */ - protected boolean dynamicFetch; + /** Field dynamicFetch */ + protected boolean dynamicFetch; - /** Field connection */ - protected PyConnection connection; + /** Field connection */ + protected PyConnection connection; - /** Field datahandler */ - protected DataHandler datahandler; + /** Field datahandler */ + protected DataHandler datahandler; - /** Field statement */ - protected PyStatement statement; + /** Field statement */ + protected PyStatement statement; - // they are stateless instances, so we only need to instantiate it once - private static final DataHandler DATAHANDLER = DataHandler.getSystemDataHandler(); + // they are stateless instances, so we only need to instantiate it once + private static final DataHandler DATAHANDLER = DataHandler.getSystemDataHandler(); - /** - * Create the cursor with a static fetch. - * - * @param connection - */ - PyCursor(PyConnection connection) { - this(connection, false); - } + /** + * Create the cursor with a static fetch. + * + * @param connection + */ + PyCursor(PyConnection connection) { + this(connection, false); + } - /** - * Create the cursor, optionally choosing the type of fetch (static or dynamic). - * If dynamicFetch is true, then use a dynamic fetch. - * - * @param connection - * @param dynamicFetch - */ - PyCursor(PyConnection connection, boolean dynamicFetch) { + /** + * Create the cursor, optionally choosing the type of fetch (static or dynamic). + * If dynamicFetch is true, then use a dynamic fetch. + * + * @param connection + * @param dynamicFetch + */ + PyCursor(PyConnection connection, boolean dynamicFetch) { + this.arraysize = 1; + this.softspace = 0; + this.closed = false; + this.rsType = Py.None; + this.rsConcur = Py.None; + this.connection = connection; + this.datahandler = DATAHANDLER; + this.dynamicFetch = dynamicFetch; - this.arraysize = 1; - this.softspace = 0; - this.closed = false; - this.rsType = Py.None; - this.rsConcur = Py.None; - this.connection = connection; - this.datahandler = DATAHANDLER; - this.dynamicFetch = dynamicFetch; + // constructs the appropriate Fetch among other things + this.clear(); + } - // constructs the appropriate Fetch among other things - this.clear(); - } + /** + * Create the cursor, optionally choosing the type of fetch (static or dynamic). + * If dynamicFetch is true, then use a dynamic fetch. + * rsType and rsConcur are used to create the Statement if both are non-None + * + * @param connection + * @param dynamicFetch + * @param rsType + * @param rsConcur + */ + PyCursor(PyConnection connection, boolean dynamicFetch, PyObject rsType, PyObject rsConcur) { + this(connection, dynamicFetch); + this.rsType = rsType; + this.rsConcur = rsConcur; + } - /** - * Create the cursor, optionally choosing the type of fetch (static or dynamic). - * If dynamicFetch is true, then use a dynamic fetch. - * rsType and rsConcur are used to create the Statement if both are non-None - * - * @param connection - * @param dynamicFetch - * @param rsType - * @param rsConcur - */ - PyCursor(PyConnection connection, boolean dynamicFetch, PyObject rsType, PyObject rsConcur) { + /** Field __methods__ */ + protected static PyList __methods__; - this(connection, dynamicFetch); + /** Field __members__ */ + protected static PyList __members__; - this.rsType = rsType; - this.rsConcur = rsConcur; - } + static { + PyObject[] m = new PyObject[9]; - /** Field __methods__ */ - protected static PyList __methods__; + m[0] = new PyString("close"); + m[1] = new PyString("execute"); + m[2] = new PyString("executemany"); + m[3] = new PyString("fetchone"); + m[4] = new PyString("fetchall"); + m[5] = new PyString("fetchmany"); + m[6] = new PyString("callproc"); + m[7] = new PyString("next"); + m[8] = new PyString("write"); + __methods__ = new PyList(m); + m = new PyObject[11]; + m[0] = new PyString("arraysize"); + m[1] = new PyString("rowcount"); + m[2] = new PyString("rownumber"); + m[3] = new PyString("description"); + m[4] = new PyString("datahandler"); + m[5] = new PyString("warnings"); + m[6] = new PyString("lastrowid"); + m[7] = new PyString("updatecount"); + m[8] = new PyString("softspace"); + m[9] = new PyString("closed"); + m[10] = new PyString("connection"); + __members__ = new PyList(m); + } - /** Field __members__ */ - protected static PyList __members__; - - static { - PyObject[] m = new PyObject[9]; - - m[0] = new PyString("close"); - m[1] = new PyString("execute"); - m[2] = new PyString("executemany"); - m[3] = new PyString("fetchone"); - m[4] = new PyString("fetchall"); - m[5] = new PyString("fetchmany"); - m[6] = new PyString("callproc"); - m[7] = new PyString("next"); - m[8] = new PyString("write"); - __methods__ = new PyList(m); - m = new PyObject[11]; - m[0] = new PyString("arraysize"); - m[1] = new PyString("rowcount"); - m[2] = new PyString("rownumber"); - m[3] = new PyString("description"); - m[4] = new PyString("datahandler"); - m[5] = new PyString("warnings"); - m[6] = new PyString("lastrowid"); - m[7] = new PyString("updatecount"); - m[8] = new PyString("softspace"); - m[9] = new PyString("closed"); - m[10] = new PyString("connection"); - __members__ = new PyList(m); - } - - /** - * String representation of the object. - * - * @return a string representation of the object. - */ - public String toString() { - return "<PyCursor object instance at " + Py.id(this) + ">"; - } - - /** - * Sets the attribute name to value. - * - * @param name - * @param value - */ - public void __setattr__(String name, PyObject value) { - - if ("arraysize".equals(name)) { - this.arraysize = value.asInt(); - } else if ("softspace".equals(name)) { - this.softspace = value.asInt(); - } else if ("datahandler".equals(name)) { - this.datahandler = (DataHandler)value.__tojava__(DataHandler.class); - } else { - super.__setattr__(name, value); + /** + * String representation of the object. + * + * @return a string representation of the object. + */ + @Override + public String toString() { + return "<PyCursor object instance at " + Py.id(this) + ">"; } - } - /** - * Gets the value of the attribute name. - * - * @param name - * @return the attribute for the given name - */ - public PyObject __findattr_ex__(String name) { - - if ("arraysize".equals(name)) { - return Py.newInteger(arraysize); - } else if ("softspace".equals(name)) { - return Py.newInteger(softspace); - } else if ("__methods__".equals(name)) { - return __methods__; - } else if ("__members__".equals(name)) { - return __members__; - } else if ("description".equals(name)) { - return this.fetch.description; - } else if ("rowcount".equals(name)) { - return Py.newInteger(this.fetch.rowcount); - } else if ("rownumber".equals(name)) { - int rn = this.fetch.rownumber; - return (rn < 0) ? Py.None : Py.newInteger(rn); - } else if ("warnings".equals(name)) { - return warnings; - } else if ("lastrowid".equals(name)) { - return lastrowid; - } else if ("updatecount".equals(name)) { - return updatecount; - } else if ("datahandler".equals(name)) { - return Py.java2py(this.datahandler); - } else if ("dynamic".equals(name)) { - return this.dynamicFetch ? Py.One : Py.Zero; - } else if ("connection".equals(name)) { - return this.connection; - } else if ("closed".equals(name)) { - return Py.newBoolean(closed); - } else if ("callproc".equals(name)) { - try { - // dynamically decide on the the attribute based on the driver - if (!getMetaData().supportsStoredProcedures()) { - return null; + /** + * Sets the attribute name to value. + * + * @param name + * @param value + */ + @Override + public void __setattr__(String name, PyObject value) { + if ("arraysize".equals(name)) { + this.arraysize = value.asInt(); + } else if ("softspace".equals(name)) { + this.softspace = value.asInt(); + } else if ("datahandler".equals(name)) { + this.datahandler = (DataHandler)value.__tojava__(DataHandler.class); + } else { + super.__setattr__(name, value); } - } catch (Throwable t) {} } - return super.__findattr_ex__(name); - } + /** + * Gets the value of the attribute name. + * + * @param name + * @return the attribute for the given name + */ + @Override + public PyObject __findattr_ex__(String name) { + if ("arraysize".equals(name)) { + return Py.newInteger(arraysize); + } else if ("softspace".equals(name)) { + return Py.newInteger(softspace); + } else if ("__methods__".equals(name)) { + return __methods__; + } else if ("__members__".equals(name)) { + return __members__; + } else if ("description".equals(name)) { + return this.fetch.description; + } else if ("rowcount".equals(name)) { + return Py.newInteger(this.fetch.rowcount); + } else if ("rownumber".equals(name)) { + int rn = this.fetch.rownumber; + return (rn < 0) ? Py.None : Py.newInteger(rn); + } else if ("warnings".equals(name)) { + return warnings; + } else if ("lastrowid".equals(name)) { + return lastrowid; + } else if ("updatecount".equals(name)) { + return updatecount; + } else if ("datahandler".equals(name)) { + return Py.java2py(this.datahandler); + } else if ("dynamic".equals(name)) { + return this.dynamicFetch ? Py.One : Py.Zero; + } else if ("connection".equals(name)) { + return this.connection; + } else if ("closed".equals(name)) { + return Py.newBoolean(closed); + } else if ("callproc".equals(name)) { + try { + // dynamically decide on the the attribute based on the driver + if (!getMetaData().supportsStoredProcedures()) { + return null; + } + } catch (Throwable t) {} + } - /** - * Initializes the object's namespace. - * - * @param dict - */ - static public void classDictInit(PyObject dict) { - - dict.__setitem__("__version__", Py.newString("$Revision$").__getslice__(Py.newInteger(11), Py.newInteger(-2), null)); - dict.__setitem__("fetchmany", new CursorFunc("fetchmany", 0, 0, 1, "fetch specified number of rows")); - dict.__setitem__("close", new CursorFunc("close", 1, 0, "close the cursor")); - dict.__setitem__("fetchall", new CursorFunc("fetchall", 2, 0, "fetch all results")); - dict.__setitem__("fetchone", new CursorFunc("fetchone", 3, 0, "fetch the next result")); - dict.__setitem__("nextset", new CursorFunc("nextset", 4, 0, "return next set or None")); - dict.__setitem__("execute", new CursorFunc("execute", 5, 1, 4, "execute the sql expression")); - dict.__setitem__("setinputsizes", new CursorFunc("setinputsizes", 6, 1, "not implemented")); - dict.__setitem__("setoutputsize", new CursorFunc("setoutputsize", 7, 1, 2, "not implemented")); - dict.__setitem__("callproc", new CursorFunc("callproc", 8, 1, 4, "executes a stored procedure")); - dict.__setitem__("executemany", new CursorFunc("executemany", 9, 1, 3, "execute sql with the parameter list")); - dict.__setitem__("scroll", new CursorFunc("scroll", 10, 1, 2, "scroll the cursor in the result set to a new position according to mode")); - dict.__setitem__("write", new CursorFunc("write", 11, 1, "execute the sql written to this file-like object")); - dict.__setitem__("prepare", new CursorFunc("prepare", 12, 1, "prepare the sql statement for later execution")); - - // hide from python - dict.__setitem__("classDictInit", null); - dict.__setitem__("toString", null); - dict.__setitem__("getDataHandler", null); - dict.__setitem__("warning", null); - dict.__setitem__("fetch", null); - dict.__setitem__("statement", null); - dict.__setitem__("dynamicFetch", null); - dict.__setitem__("getPyClass", null); - dict.__setitem__("rsConcur", null); - dict.__setitem__("rsType", null); - } - - /** - * Delete the cursor. - * - */ - public void __del__() { - close(); - } - - /** - * Close the cursor now (rather than whenever __del__ is called). - * The cursor will be unusable from this point forward; an Error - * (or subclass) exception will be raised if any operation is - * attempted with the cursor. - * - */ - public void close() { - - try { - this.clear(); - this.connection.remove(this); - } finally { - this.closed = true; + return super.__findattr_ex__(name); } - } - /** - * Returns an iteratable object. - * - * @return PyObject - * - * @since Jython 2.2, DB API 2.0+ - */ - public PyObject __iter__() { - return this; - } + /** + * Initializes the object's namespace. + * + * @param dict + */ + static public void classDictInit(PyObject dict) { + PyObject version = + Py.newString("$Revision$").__getslice__(Py.newInteger(11), + Py.newInteger(-2)); + dict.__setitem__("__version__", version); + dict.__setitem__("fetchmany", new CursorFunc("fetchmany", 0, 0, 1, "fetch specified number of rows")); + dict.__setitem__("close", new CursorFunc("close", 1, 0, "close the cursor")); + dict.__setitem__("fetchall", new CursorFunc("fetchall", 2, 0, "fetch all results")); + dict.__setitem__("fetchone", new CursorFunc("fetchone", 3, 0, "fetch the next result")); + dict.__setitem__("nextset", new CursorFunc("nextset", 4, 0, "return next set or None")); + dict.__setitem__("execute", new CursorFunc("execute", 5, 1, 4, "execute the sql expression")); + dict.__setitem__("setinputsizes", new CursorFunc("setinputsizes", 6, 1, "not implemented")); + dict.__setitem__("setoutputsize", new CursorFunc("setoutputsize", 7, 1, 2, "not implemented")); + dict.__setitem__("callproc", new CursorFunc("callproc", 8, 1, 4, "executes a stored procedure")); + dict.__setitem__("executemany", new CursorFunc("executemany", 9, 1, 3, "execute sql with the parameter list")); + dict.__setitem__("scroll", new CursorFunc("scroll", 10, 1, 2, "scroll the cursor in the result set to a new position according to mode")); + dict.__setitem__("write", new CursorFunc("write", 11, 1, "execute the sql written to this file-like object")); + dict.__setitem__("prepare", new CursorFunc("prepare", 12, 1, "prepare the sql statement for later execution")); - /** - * Returns the next row from the currently executing SQL statement - * using the same semantics as .fetchone(). A StopIteration - * exception is raised when the result set is exhausted for Python - * versions 2.2 and later. - * - * @return PyObject - * - * @since Jython 2.2, DB API 2.0+ - */ - public PyObject next() { - PyObject row = __iternext__(); - if (row == null) { - throw Py.StopIteration(""); + // hide from python + dict.__setitem__("classDictInit", null); + dict.__setitem__("toString", null); + dict.__setitem__("getDataHandler", null); + dict.__setitem__("warning", null); + dict.__setitem__("fetch", null); + dict.__setitem__("statement", null); + dict.__setitem__("dynamicFetch", null); + dict.__setitem__("getPyClass", null); + dict.__setitem__("rsConcur", null); + dict.__setitem__("rsType", null); } - return row; - } - /** - * Return the next element of the sequence that this is an iterator - * for. Returns null when the end of the sequence is reached. - * - * @since Jython 2.2 - * - * @return PyObject - */ - public PyObject __iternext__() { - PyObject row = fetchone(); - return row.__nonzero__() ? row : null; - } - - /** - * Return ths DatabaseMetaData for the current connection. - * - * @return DatabaseMetaData - * - * @throws SQLException - */ - protected DatabaseMetaData getMetaData() throws SQLException { - return this.connection.connection.getMetaData(); - } - - /** - * Return the currently bound DataHandler. - * - * @return DataHandler - */ - public DataHandler getDataHandler() { - return this.datahandler; - } - - /** - * Prepare a statement ready for executing. - * - * @param sql the sql to execute or a prepared statement - * @param maxRows max number of rows to be returned - * @param prepared if true, prepare the statement, otherwise create a normal statement - * - * @return PyStatement - */ - private PyStatement prepareStatement(PyObject sql, PyObject maxRows, boolean prepared) { - - PyStatement stmt = null; - - if (sql == Py.None) { - return null; + /** + * Delete the cursor. + * + */ + public void __del__() { + close(); } - try { - if (sql instanceof PyStatement) { - stmt = (PyStatement)sql; - } else { - Statement sqlStatement = null; - String sqlString = sql.__str__().toString(); - - if (sqlString.trim().length() == 0) { - return null; + /** + * Close the cursor now (rather than whenever __del__ is called). + * The cursor will be unusable from this point forward; an Error + * (or subclass) exception will be raised if any operation is + * attempted with the cursor. + * + */ + public void close() { + try { + this.clear(); + this.connection.remove(this); + } finally { + this.closed = true; } + } - boolean normal = ((this.rsType == Py.None) && (this.rsConcur == Py.None)); + /** + * Returns an iteratable object. + * + * @return PyObject + * + * @since Jython 2.2, DB API 2.0+ + */ + @Override + public PyObject __iter__() { + return this; + } - if (normal) { - if (prepared) { - sqlStatement = this.connection.connection.prepareStatement(sqlString); - } else { - sqlStatement = this.connection.connection.createStatement(); - } - } else { - int t = this.rsType.asInt(); - int c = this.rsConcur.asInt(); - - if (prepared) { - sqlStatement = this.connection.connection.prepareStatement(sqlString, t, c); - } else { - sqlStatement = this.connection.connection.createStatement(t, c); - } + /** + * Returns the next row from the currently executing SQL statement + * using the same semantics as .fetchone(). A StopIteration + * exception is raised when the result set is exhausted for Python + * versions 2.2 and later. + * + * @return PyObject + * + * @since Jython 2.2, DB API 2.0+ + */ + public PyObject next() { + PyObject row = __iternext__(); + if (row == null) { + throw Py.StopIteration(""); } + return row; + } - int style = prepared ? PyStatement.STATEMENT_PREPARED : PyStatement.STATEMENT_STATIC; + /** + * Return the next element of the sequence that this is an iterator + * for. Returns null when the end of the sequence is reached. + * + * @since Jython 2.2 + * + * @return PyObject + */ + @Override + public PyObject __iternext__() { + PyObject row = fetchone(); + return row.__nonzero__() ? row : null; + } - stmt = new PyStatement(sqlStatement, sqlString, style); - } + /** + * Return ths DatabaseMetaData for the current connection. + * + * @return DatabaseMetaData + * + * @throws SQLException + */ + protected DatabaseMetaData getMetaData() throws SQLException { + return this.connection.connection.getMetaData(); + } - if (maxRows != Py.None) { - stmt.statement.setMaxRows(maxRows.asInt()); - } - } catch (AbstractMethodError e) { - throw zxJDBC.makeException(zxJDBC.NotSupportedError, zxJDBC.getString("nodynamiccursors")); - } catch (PyException e) { - throw e; - } catch (Throwable e) { - throw zxJDBC.makeException(e); + /** + * Return the currently bound DataHandler. + * + * @return DataHandler + */ + public DataHandler getDataHandler() { + return this.datahandler; } - return stmt; - } + /** + * Prepare a statement ready for executing. + * + * @param sql the sql to execute or a prepared statement + * @param maxRows max number of rows to be returned + * @param prepared if true, prepare the statement, otherwise create a normal statement + * + * @return PyStatement + */ + private PyStatement prepareStatement(PyObject sql, PyObject maxRows, boolean prepared) { + PyStatement stmt = null; - /** - * This method is optional since not all databases provide stored procedures. - * - * Call a stored database procedure with the given name. The sequence of parameters - * must contain one entry for each argument that the procedure expects. The result of - * the call is returned as modified copy of the input sequence. Input parameters are - * left untouched, output and input/output parameters replaced with possibly new values. - * - * The procedure may also provide a result set as output. This must then be made available - * through the standard fetchXXX() methods. - * - * @param name - * @param params - * @param bindings - * @param maxRows - */ - public void callproc(PyObject name, final PyObject params, PyObject bindings, PyObject maxRows) { + if (sql == Py.None) { + return null; + } - this.clear(); + try { + if (sql instanceof PyStatement) { + stmt = (PyStatement)sql; + } else { + Statement sqlStatement = null; + String sqlString = sql.__str__().toString(); - try { - if (getMetaData().supportsStoredProcedures()) { - if (isSeqSeq(params)) { - throw zxJDBC.makeException(zxJDBC.NotSupportedError, "sequence of sequences is not supported"); - } + if (sqlString.trim().length() == 0) { + return null; + } - final Procedure procedure = datahandler.getProcedure(this, name); - Statement stmt = procedure.prepareCall(this.rsType, this.rsConcur); + boolean normal = (this.rsType == Py.None && this.rsConcur == Py.None); - if (maxRows != Py.None) { - stmt.setMaxRows(maxRows.asInt()); - } + if (normal) { + if (prepared) { + sqlStatement = this.connection.connection.prepareStatement(sqlString); + } else { + sqlStatement = this.connection.connection.createStatement(); + } + } else { + int t = this.rsType.asInt(); + int c = this.rsConcur.asInt(); - // get the bindings per the stored proc spec - PyDictionary callableBindings = new PyDictionary(); + if (prepared) { + sqlStatement = this.connection.connection.prepareStatement(sqlString, t, + c); + } else { + sqlStatement = this.connection.connection.createStatement(t, c); + } + } - procedure.normalizeInput(params, callableBindings); + int style = prepared + ? PyStatement.STATEMENT_PREPARED : PyStatement.STATEMENT_STATIC; - // overwrite with any user specific bindings - if (bindings instanceof PyDictionary) { - callableBindings.update(bindings); + stmt = new PyStatement(sqlStatement, sqlString, style); + } + + if (maxRows != Py.None) { + stmt.statement.setMaxRows(maxRows.asInt()); + } + } catch (AbstractMethodError e) { + throw zxJDBC.makeException(zxJDBC.NotSupportedError, + zxJDBC.getString("nodynamiccursors")); + } catch (PyException e) { + throw e; + } catch (Throwable e) { + throw zxJDBC.makeException(e); } - this.statement = new PyStatement(stmt, procedure); - - this.execute(params, callableBindings); - } else { - throw zxJDBC.makeException(zxJDBC.NotSupportedError, zxJDBC.getString("noStoredProc")); - } - } catch (PyException e) { - throw e; - } catch (Throwable e) { - throw zxJDBC.makeException(e); - } finally { - if (this.statement != null) { - - // close what we opened - this.statement.close(); - } + return stmt; } - } - /** - * Prepare a database operation (query or command) and then execute it against all - * parameter sequences or mappings found in the sequence seq_of_parameters. - * Modules are free to implement this method using multiple calls to the execute() - * method or by using array operations to have the database process the sequence as - * a whole in one call. - * - * The same comments as for execute() also apply accordingly to this method. - * - * Return values are not defined. - * - * @param sql - * @param params - * @param bindings - * @param maxRows - */ - public void executemany(PyObject sql, PyObject params, PyObject bindings, PyObject maxRows) { - if (isSeq(params) && params.__len__() == 0) { - //executemany with an empty params tuple is a no-op - return; - } - execute(sql, params, bindings, maxRows); - } + /** + * This method is optional since not all databases provide stored procedures. + * + * Call a stored database procedure with the given name. The sequence of parameters + * must contain one entry for each argument that the procedure expects. The result of + * the call is returned as modified copy of the input sequence. Input parameters are + * left untouched, output and input/output parameters replaced with possibly new values. + * + * The procedure may also provide a result set as output. This must then be made available + * through the standard fetchXXX() methods. + * + * @param name + * @param params + * @param bindings + * @param maxRows + */ + public void callproc(PyObject name, final PyObject params, PyObject bindings, + PyObject maxRows) { + this.clear(); - /** - * Prepare and execute a database operation (query or command). - * Parameters may be provided as sequence or mapping and will - * be bound to variables in the operation. Variables are specified - * in a database-specific notation (see the module's paramstyle - * attribute for details). - * - * A reference to the operation will be retained by the cursor. - * If the same operation object is passed in again, then the cursor - * can optimize its behavior. This is most effective for algorithms - * where the same operation is used, but different parameters are - * bound to it (many times). - * - * For maximum efficiency when reusing an operation, it is best to - * use the setinputsizes() method to specify the parameter types and - * sizes ahead of time. It is legal for a parameter to not match the - * predefined information; the implementation should compensate, possibly - * with a loss of efficiency. - * - * The parameters may also be specified as list of tuples to e.g. insert - * multiple rows in a single operation, but this kind of usage is - * deprecated: executemany() should be used instead. - * - * Return values are not defined. - * - * @param sql sql string or prepared statement - * @param params params for a prepared statement - * @param bindings dictionary of (param index : SQLType binding) - * @param maxRows integer value of max rows - */ - public void execute(final PyObject sql, PyObject params, PyObject bindings, PyObject maxRows) { - int rowIndex = -1; - this.clear(); + try { + if (getMetaData().supportsStoredProcedures()) { + if (isSeqSeq(params)) { + throw zxJDBC.makeException(zxJDBC.NotSupportedError, + "sequence of sequences is not supported"); + } - boolean hasParams = hasParams(params); - PyStatement stmt = this.prepareStatement(sql, maxRows, hasParams); + final Procedure procedure = datahandler.getProcedure(this, name); + Statement stmt = procedure.prepareCall(this.rsType, this.rsConcur); - if (stmt == null) { - return; - } + if (maxRows != Py.None) { + stmt.setMaxRows(maxRows.asInt()); + } - this.statement = stmt; + // get the bindings per the stored proc spec + PyDictionary callableBindings = new PyDictionary(); - try { - synchronized (this.statement) { - if (hasParams) { + procedure.normalizeInput(params, callableBindings); - // if we have a sequence of sequences, let's run through them and finish - if (isSeqSeq(params)) { + // overwrite with any user specific bindings + if (bindings instanceof PyDictionary) { + callableBindings.update(bindings); + } - // [(3, 4)] or [(3, 4), (5, 6)] - rowIndex = 0; - for (int i = 0, len = params.__len__(); i < len; i++) { - PyObject param = params.__getitem__(i); + this.statement = new PyStatement(stmt, procedure); - this.execute(param, bindings); - rowIndex++; + this.execute(params, callableBindings); + } else { + throw zxJDBC.makeException(zxJDBC.NotSupportedError, + zxJDBC.getString("noStoredProc")); } - } else { - this.execute(params, bindings); - } - } else { - - // execute the sql string straight up - this.execute(Py.None, Py.None); + } catch (PyException e) { + throw e; + } catch (Throwable e) { + throw zxJDBC.makeException(e); + } finally { + if (this.statement != null) { + // close what we opened + this.statement.close(); + } } - } - } catch (PyException e) { - throw e; - } catch (Throwable e) { - throw zxJDBC.makeException(zxJDBC.Error, e, rowIndex); - } finally { - if (this.statement != null) { + } - // only close static, single-use statements - if (!(sql instanceof PyStatement) && (!this.dynamicFetch)) { - this.statement.close(); + /** + * Prepare a database operation (query or command) and then execute it against all + * parameter sequences or mappings found in the sequence seq_of_parameters. + * Modules are free to implement this method using multiple calls to the execute() + * method or by using array operations to have the database process the sequence as + * a whole in one call. + * + * The same comments as for execute() also apply accordingly to this method. + * + * Return values are not defined. + * + * @param sql + * @param params + * @param bindings + * @param maxRows + */ + public void executemany(PyObject sql, PyObject params, PyObject bindings, PyObject maxRows) { + if (isSeq(params) && params.__len__() == 0) { + //executemany with an empty params tuple is a no-op + return; } - } + execute(sql, params, bindings, maxRows); } - } - /** - * Execute the current sql statement. Some generic functionality such - * as updating the lastrowid and updatecount occur as well. - */ - protected void execute(PyObject params, PyObject bindings) { + /** + * Prepare and execute a database operation (query or command). + * Parameters may be provided as sequence or mapping and will + * be bound to variables in the operation. Variables are specified + * in a database-specific notation (see the module's paramstyle + * attribute for details). + * + * A reference to the operation will be retained by the cursor. + * If the same operation object is passed in again, then the cursor + * can optimize its behavior. This is most effective for algorithms + * where the same operation is used, but different parameters are + * bound to it (many times). + * + * For maximum efficiency when reusing an operation, it is best to + * use the setinputsizes() method to specify the parameter types and + * sizes ahead of time. It is legal for a parameter to not match the + * predefined information; the implementation should compensate, possibly + * with a loss of efficiency. + * + * The parameters may also be specified as list of tuples to e.g. insert + * multiple rows in a single operation, but this kind of usage is + * deprecated: executemany() should be used instead. + * + * Return values are not defined. + * + * @param sql sql string or prepared statement + * @param params params for a prepared statement + * @param bindings dictionary of (param index : SQLType binding) + * @param maxRows integer value of max rows + */ + public void execute(final PyObject sql, PyObject params, PyObject bindings, PyObject maxRows) { + int rowIndex = -1; + this.clear(); - try { - Statement stmt = this.statement.statement; + boolean hasParams = hasParams(params); + PyStatement stmt = this.prepareStatement(sql, maxRows, hasParams); - this.datahandler.preExecute(stmt); + if (stmt == null) { + return; + } - // this performs the SQL execution and fetch per the Statement type - this.statement.execute(this, params, bindings); + this.statement = stmt; - this.lastrowid = this.datahandler.getRowId(stmt); + try { + synchronized (this.statement) { + if (hasParams) { - int uc = stmt.getUpdateCount(); + // if we have a sequence of sequences, let's run through them and finish + if (isSeqSeq(params)) { - this.updatecount = (uc < 0) ? Py.None : Py.newInteger(uc); + // [(3, 4)] or [(3, 4), (5, 6)] + rowIndex = 0; + for (int i = 0, len = params.__len__(); i < len; i++) { + PyObject param = params.__getitem__(i); - warning(new WarningEvent(this, stmt.getWarnings())); - this.datahandler.postExecute(stmt); - } catch (PyException e) { - throw e; - } catch (Throwable e) { - throw zxJDBC.makeException(e); + this.execute(param, bindings); + rowIndex++; + } + } else { + this.execute(params, bindings); + } + } else { + // execute the sql string straight up + this.execute(Py.None, Py.None); + } + } + } catch (PyException e) { + throw e; + } catch (Throwable e) { + throw zxJDBC.makeException(zxJDBC.Error, e, rowIndex); + } finally { + if (this.statement != null) { + // only close static, single-use statements + if (!(sql instanceof PyStatement) && !this.dynamicFetch) { + this.statement.close(); + } + } + } } - } - /** - * Fetch the next row of a query result set, returning a single sequence, - * or None when no more data is available. - * - * An Error (or subclass) exception is raised if the previous call to - * executeXXX() did not produce any result set or no call was issued yet. - * - * @return a single sequence from the result set, or None when no more data is available - */ - public PyObject fetchone() { - return this.fetch.fetchone(); - } + /** + * Execute the current sql statement. Some generic functionality such + * as updating the lastrowid and updatecount occur as well. + */ + protected void execute(PyObject params, PyObject bindings) { + try { + Statement stmt = this.statement.statement; - /** - * Fetch all (remaining) rows of a query result, returning them as a sequence - * of sequences (e.g. a list of tuples). Note that the cursor's arraysize attribute - * can affect the performance of this operation. - * - * An Error (or subclass) exception is raised if the previous call to executeXXX() - * did not produce any result set or no call was issued yet. - * - * @return a sequence of sequences from the result set, or an empty sequence when - * no more data is available - */ - public PyObject fetchall() { - return this.fetch.fetchall(); - } + this.datahandler.preExecute(stmt); - /** - * Fetch the next set of rows of a query result, returning a sequence of - * sequences (e.g. a list of tuples). An empty sequence is returned when - * no more rows are available. - * - * The number of rows to fetch per call is specified by the parameter. If - * it is not given, the cursor's arraysize determines the number of rows - * to be fetched. The method should try to fetch as many rows as indicated - * by the size parameter. If this is not possible due to the specified number - * of rows not being available, fewer rows may be returned. - * - * An Error (or subclass) exception is raised if the previous call to executeXXX() - * did not produce any result set or no call was issued yet. - * - * Note there are performance considerations involved with the size parameter. - * For optimal performance, it is usually best to use the arraysize attribute. - * If the size parameter is used, then it is best for it to retain the same value - * from one fetchmany() call to the next. - * - * @param size - * @return a sequence of sequences from the result set, or an empty sequence when - * no more data is available - */ - public PyObject fetchmany(int size) { - return this.fetch.fetchmany(size); - } + // this performs the SQL execution and fetch per the Statement type + this.statement.execute(this, params, bindings); - /** - * Move the result pointer to the next set if available. - * - * @return true if more sets exist, else None - */ - public PyObject nextset() { - return this.fetch.nextset(); - } + this.lastrowid = this.datahandler.getRowId(stmt); - /** - * Prepare a sql statement for later execution. - * - * @param sql The sql string to be prepared. - * - * @return A prepared statement usable with .executeXXX() - */ - public PyStatement prepare(PyObject sql) { + int uc = stmt.getUpdateCount(); - PyStatement s = this.prepareStatement(sql, Py.None, true); + this.updatecount = uc < 0 ? Py.None : Py.newInteger(uc); - // add to the set of statements which are leaving our control - this.connection.add(s); + warning(new WarningEvent(this, stmt.getWarnings())); + this.datahandler.postExecute(stmt); + } catch (PyException e) { + throw e; + } catch (Throwable e) { + throw zxJDBC.makeException(e); + } + } - return s; - } + /** + * Fetch the next row of a query result set, returning a single sequence, + * or None when no more data is available. + * + * An Error (or subclass) exception is raised if the previous call to + * executeXXX() did not produce any result set or no call was issued yet. + * + * @return a single sequence from the result set, or None when no more data is available + */ + public PyObject fetchone() { + return this.fetch.fetchone(); + } - /** - * Scroll the cursor in the result set to a new position according - * to mode. - * - * If mode is 'relative' (default), value is taken as offset to - * the current position in the result set, if set to 'absolute', - * value states an absolute target position. - * - * An IndexError should be raised in case a scroll operation would - * leave the result set. In this case, the cursor position is left - * undefined (ideal would be to not move the cursor at all). - * - * Note: This method should use native scrollable cursors, if - * available, or revert to an emulation for forward-only - * scrollable cursors. The method may raise NotSupportedErrors to - * signal that a specific operation is not supported by the - * database (e.g. backward scrolling). - * - * - * @param value - * @param mode - * - */ - public void scroll(int value, String mode) { - this.fetch.scroll(value, mode); - } + /** + * Fetch all (remaining) rows of a query result, returning them as a sequence + * of sequences (e.g. a list of tuples). Note that the cursor's arraysize attribute + * can affect the performance of this operation. + * + * An Error (or subclass) exception is raised if the previous call to executeXXX() + * did not produce any result set or no call was issued yet. + * + * @return a sequence of sequences from the result set, or an empty sequence when + * no more data is available + */ + public PyObject fetchall() { + return this.fetch.fetchall(); + } - /** - * Adds a warning to the tuple and will follow the chain as necessary. - * - * @param event - */ - public void warning(WarningEvent event) { + /** + * Fetch the next set of rows of a query result, returning a sequence of + * sequences (e.g. a list of tuples). An empty sequence is returned when + * no more rows are available. + * + * The number of rows to fetch per call is specified by the parameter. If + * it is not given, the cursor's arraysize determines the number of rows + * to be fetched. The method should try to fetch as many rows as indicated + * by the size parameter. If this is not possible due to the specified number + * of rows not being available, fewer rows may be returned. + * + * An Error (or subclass) exception is raised if the previous call to executeXXX() + * did not produce any result set or no call was issued yet. + * + * Note there are performance considerations involved with the size parameter. + * For optimal performance, it is usually best to use the arraysize attribute. + * If the size parameter is used, then it is best for it to retain the same value + * from one fetchmany() call to the next. + * + * @param size + * @return a sequence of sequences from the result set, or an empty sequence when + * no more data is available + */ + public PyObject fetchmany(int size) { + return this.fetch.fetchmany(size); + } - if (this.warnings == Py.None) { - this.warnings = new PyList(); + /** + * Move the result pointer to the next set if available. + * + * @return true if more sets exist, else None + */ + public PyObject nextset() { + return this.fetch.nextset(); } - SQLWarning warning = event.getWarning(); - while(warning != null) { + /** + * Prepare a sql statement for later execution. + * + * @param sql The sql string to be prepared. + * + * @return A prepared statement usable with .executeXXX() + */ + public PyStatement prepare(PyObject sql) { + PyStatement s = this.prepareStatement(sql, Py.None, true); - PyObject[] warn = new PyObject[] { - // there are three parts: (reason, state, vendorCode) - Py.java2py(warning.getMessage()), - Py.java2py(warning.getSQLState()), - Py.newInteger(warning.getErrorCode()) - }; + // add to the set of statements which are leaving our control + this.connection.add(s); - // add the warning to the list - ((PyList)this.warnings).append(new PyTuple(warn)); - - warning = warning.getNextWarning(); + return s; } - } - /** - * Resets the cursor state. This includes flushing the warnings - * and any previous results. - * - */ - protected void clear() { - - if (closed) { - throw zxJDBC.makeException(zxJDBC.ProgrammingError, "cursor is closed"); + /** + * Scroll the cursor in the result set to a new position according + * to mode. + * + * If mode is 'relative' (default), value is taken as offset to + * the current position in the result set, if set to 'absolute', + * value states an absolute target position. + * + * An IndexError should be raised in case a scroll operation would + * leave the result set. In this case, the cursor position is left + * undefined (ideal would be to not move the cursor at all). + * + * Note: This method should use native scrollable cursors, if + * available, or revert to an emulation for forward-only + * scrollable cursors. The method may raise NotSupportedErrors to + * signal that a specific operation is not supported by the + * database (e.g. backward scrolling). + * + * + * @param value + * @param mode + * + */ + public void scroll(int value, String mode) { + this.fetch.scroll(value, mode); } - this.warnings = Py.None; - this.lastrowid = Py.None; - this.updatecount = Py.newInteger(-1); + /** + * Adds a warning to the tuple and will follow the chain as necessary. + * + * @param event + */ + public void warning(WarningEvent event) { + if (this.warnings == Py.None) { + this.warnings = new PyList(); + } - try { - this.fetch.close(); - } catch (Throwable e) {} - finally { - this.fetch = Fetch.newFetch(this.datahandler, this.dynamicFetch); + SQLWarning warning = event.getWarning(); + while (warning != null) { + PyObject[] warn = new PyObject[] { + // there are three parts: (reason, state, vendorCode) + Py.java2py(warning.getMessage()), + Py.java2py(warning.getSQLState()), + Py.newInteger(warning.getErrorCode()) + }; - this.fetch.addWarningListener(this); - } + // add the warning to the list + ((PyList)this.warnings).append(new PyTuple(warn)); - if (this.statement != null) { - - // we can't close a dynamic fetch statement until everything has been - // consumed so the only time we can clean up is now - // but if this is a previously prepared statement we don't want to close - // it underneath someone; we can check this by looking in the set - try { - if (this.dynamicFetch && (!this.connection.contains(this.statement))) { - this.statement.close(); + warning = warning.getNextWarning(); } - } finally { - this.statement = null; - } } - } - /** - * Method isSeq - * - * @param object - * - * @return true for any PyList, PyTuple or java.util.List - * - */ - public static boolean isSeq(PyObject object) { + /** + * Resets the cursor state. This includes flushing the warnings + * and any previous results. + * + */ + protected void clear() { + if (closed) { + throw zxJDBC.makeException(zxJDBC.ProgrammingError, "cursor is closed"); + } - if ((object == null) || (object == Py.None)) { - return false; - } + this.warnings = Py.None; + this.lastrowid = Py.None; + this.updatecount = Py.newInteger(-1); - if (object.__tojava__(List.class) != Py.NoConversion) { - return true; + try { + this.fetch.close(); + } catch (Throwable e) { + // ok + } finally { + this.fetch = Fetch.newFetch(this.datahandler, this.dynamicFetch); + this.fetch.addWarningListener(this); + } + + if (this.statement != null) { + // we can't close a dynamic fetch statement until everything has been + // consumed so the only time we can clean up is now + // but if this is a previously prepared statement we don't want to close + // it underneath someone; we can check this by looking in the set + try { + if (this.dynamicFetch && !this.connection.contains(this.statement)) { + this.statement.close(); + } + } finally { + this.statement = null; + } + } } - // originally checked for __getitem__ and __len__, but this is true for PyString - // and we don't want to insert one character at a time - return (object instanceof PyList) || (object instanceof PyTuple); - } + /** + * Method isSeq + * + * @param object + * + * @return true for any PyList, PyTuple or java.util.List + * + */ + public static boolean isSeq(PyObject object) { + if (object == null || object == Py.None) { + return false; + } - /** - * Method hasParams - * - * @param params - * - * @return boolean - * - */ - public static boolean hasParams(PyObject params) { - if(Py.None == params) { - return false; - } + if (object.__tojava__(List.class) != Py.NoConversion) { + return true; + } - boolean isSeq = isSeq(params); - // the optional argument better be a sequence - if (!isSeq) { - throw zxJDBC.makeException(zxJDBC.ProgrammingError, zxJDBC.getString("optionalSecond")); + // originally checked for __getitem__ and __len__, but this is true for PyString + // and we don't want to insert one character at a time + return object instanceof PyList || object instanceof PyTuple; } - return params.__len__() > 0; - } - /** - * Method isSeqSeq - * - * @param object - * - * @return true is a sequence of sequences - * - */ - public static boolean isSeqSeq(PyObject object) { + /** + * Method hasParams + * + * @param params + * + * @return boolean + * + */ + public static boolean hasParams(PyObject params) { + if (Py.None == params) { + return false; + } - if (isSeq(object) && (object.__len__() > 0)) { - for (int i = 0; i < object.__len__(); i++) { - if (!isSeq(object.__finditem__(i))) { - return false; + boolean isSeq = isSeq(params); + // the optional argument better be a sequence + if (!isSeq) { + throw zxJDBC.makeException(zxJDBC.ProgrammingError, + zxJDBC.getString("optionalSecond")); } - } - return true; + return params.__len__() > 0; } - return false; - } + + /** + * Method isSeqSeq + * + * @param object + * + * @return true is a sequence of sequences + * + */ + public static boolean isSeqSeq(PyObject object) { + if (isSeq(object) && (object.__len__() > 0)) { + for (int i = 0; i < object.__len__(); i++) { + if (!isSeq(object.__finditem__(i))) { + return false; + } + } + return true; + } + return false; + } } class CursorFunc extends PyBuiltinMethodSet { - CursorFunc(String name, int index, int argcount, String doc) { - this(name, index, argcount, argcount, doc); - } - CursorFunc(String name, int index, int minargs, int maxargs, String doc) { - super(name, index, minargs, maxargs, doc, PyCursor.class); - } - public PyObject __call__() { - PyCursor cursor = (PyCursor)__self__; - switch (index) { - case 0 : - return cursor.fetchmany(cursor.arraysize); - case 1 : - cursor.close(); - return Py.None; - case 2 : - return cursor.fetchall(); - case 3 : - return cursor.fetchone(); - case 4 : - return cursor.nextset(); - default : - throw info.unexpectedCall(0, false); + CursorFunc(String name, int index, int argcount, String doc) { + this(name, index, argcount, argcount, doc); } - } - public PyObject __call__(PyObject arg) { - PyCursor cursor = (PyCursor)__self__; - switch (index) { - case 0 : - return cursor.fetchmany(arg.asInt()); - case 5 : - cursor.execute(arg, Py.None, Py.None, Py.None); - return Py.None; - case 6 : - case 7 : - return Py.None; - case 8 : - cursor.callproc(arg, Py.None, Py.None, Py.None); - return Py.None; - case 9 : - cursor.executemany(arg, Py.None, Py.None, Py.None); - return Py.None; - case 10 : - cursor.scroll(arg.asInt(), "relative"); - return Py.None; - case 11 : - cursor.execute(arg, Py.None, Py.None, Py.None); - return Py.None; - case 12 : - return cursor.prepare(arg); - default : - throw info.unexpectedCall(1, false); + CursorFunc(String name, int index, int minargs, int maxargs, String doc) { + super(name, index, minargs, maxargs, doc, PyCursor.class); } - } - public PyObject __call__(PyObject arga, PyObject argb) { - PyCursor cursor = (PyCursor)__self__; - switch (index) { - case 5 : - cursor.execute(arga, argb, Py.None, Py.None); - return Py.None; - case 7 : - return Py.None; - case 8 : - cursor.callproc(arga, argb, Py.None, Py.None); - return Py.None; - case 9 : - cursor.executemany(arga, argb, Py.None, Py.None); - return Py.None; - case 10 : - cursor.scroll(arga.asInt(), argb.toString()); - return Py.None; - default : - throw info.unexpectedCall(2, false); + @Override + public PyObject __call__() { + PyCursor cursor = (PyCursor)__self__; + switch (index) { + case 0 : + return cursor.fetchmany(cursor.arraysize); + case 1 : + cursor.close(); + return Py.None; + case 2 : + return cursor.fetchall(); + case 3 : + return cursor.fetchone(); + case 4 : + return cursor.nextset(); + default : + throw info.unexpectedCall(0, false); + } } - } - public PyObject __call__(PyObject arga, PyObject argb, PyObject argc) { - PyCursor cursor = (PyCursor)__self__; - switch (index) { - case 5 : - cursor.execute(arga, argb, argc, Py.None); - return Py.None; - case 8 : - cursor.callproc(arga, argb, argc, Py.None); - return Py.None; - case 9 : - cursor.executemany(arga, argb, argc, Py.None); - return Py.None; - default : - throw info.unexpectedCall(3, false); + @Override + public PyObject __call__(PyObject arg) { + PyCursor cursor = (PyCursor)__self__; + switch (index) { + case 0 : + return cursor.fetchmany(arg.asInt()); + case 5 : + cursor.execute(arg, Py.None, Py.None, Py.None); + return Py.None; + case 6 : + case 7 : + return Py.None; + case 8 : + cursor.callproc(arg, Py.None, Py.None, Py.None); + return Py.None; + case 9 : + cursor.executemany(arg, Py.None, Py.None, Py.None); + return Py.None; + case 10 : + cursor.scroll(arg.asInt(), "relative"); + return Py.None; + case 11 : + cursor.execute(arg, Py.None, Py.None, Py.None); + return Py.None; + case 12 : + return cursor.prepare(arg); + default : + throw info.unexpectedCall(1, false); + } } - } - public PyObject __call__(PyObject[] args, String[] keywords) { + @Override + public PyObject __call__(PyObject arga, PyObject argb) { + PyCursor cursor = (PyCursor)__self__; + switch (index) { + case 5 : + cursor.execute(arga, argb, Py.None, Py.None); + return Py.None; + case 7 : + return Py.None; + case 8 : + cursor.callproc(arga, argb, Py.None, Py.None); + return Py.None; + case 9 : + cursor.executemany(arga, argb, Py.None, Py.None); + return Py.None; + case 10 : + cursor.scroll(arga.asInt(), argb.toString()); + return Py.None; + default : + throw info.unexpectedCall(2, false); + } + } - PyCursor cursor = (PyCursor)__self__; - PyArgParser parser = new PyArgParser(args, keywords); - PyObject sql = parser.arg(0); - PyObject params = parser.kw("params", Py.None); - PyObject bindings = parser.kw("bindings", P... [truncated message content] |