From: brian z. <bz...@us...> - 2002-04-19 19:08:07
|
Update of /cvsroot/jython/jython/com/ziclix/python/sql In directory usw-pr-cvs1:/tmp/cvs-serv25122/com/ziclix/python/sql Modified Files: PyCursor.java PyConnection.java Added Files: PyStatement.java Log Message: added .prepare() to cursor --- NEW FILE: PyStatement.java --- /* * Jython Database Specification API 2.0 * * $Id: PyStatement.java,v 1.1 2002/04/19 19:01:05 bzimmer Exp $ * * Copyright (c) 2001 brian zimmer <bz...@zi...> * */ package com.ziclix.python.sql; import java.sql.Statement; import java.sql.SQLException; import java.sql.PreparedStatement; import java.sql.CallableStatement; import org.python.core.*; /** * Class PyStatement * * @author brian zimmer * @date 2002-04-19 08:58:22.11 * @date last modified on $Date: 2002/04/19 19:01:05 $ * @version $Revision: 1.1 $ */ public class PyStatement extends PyObject { /** Field STATEMENT_STATIC */ public static final int STATEMENT_STATIC = 2; /** Field STATEMENT_PREPARED */ public static final int STATEMENT_PREPARED = 4; /** Field STATEMENT_CALLABLE */ public static final int STATEMENT_CALLABLE = 8; /** Field style */ protected int style; /** Field sql */ protected Object sql; /** Field closed */ boolean closed; /** Field params */ protected PyObject params; /** Field statement */ protected Statement statement; /** * Constructor PyStatement * * @param statement * @param sql * @param style * */ public PyStatement(Statement statement, Object sql, int style) { this.sql = sql; this.style = style; this.closed = false; this.statement = statement; } /** * Constructor PyStatement * * @param statement * @param procedure * @param params * */ public PyStatement(Statement statement, Procedure procedure, PyObject params) { this(statement, procedure, STATEMENT_CALLABLE); this.params = params; } /** Field __class__ */ public static PyClass __class__; /** * Method getPyClass * * @return PyClass * */ protected PyClass getPyClass() { return __class__; } /** Field __methods__ */ protected static PyList __methods__; /** Field __members__ */ protected static PyList __members__; static { PyObject[] m = new PyObject[1]; m[0] = new PyString("close"); __methods__ = new PyList(m); m = new PyObject[3]; m[0] = new PyString("style"); m[1] = new PyString("closed"); m[2] = new PyString("__statement__"); __members__ = new PyList(m); } /** * Method __str__ * * @return PyString * */ public PyString __str__() { if (sql instanceof String) { return Py.newString((String)sql); } else if (sql instanceof Procedure) { try { return Py.newString(((Procedure)sql).toSql()); } catch (SQLException e) { throw zxJDBC.makeException(e); } } return super.__str__(); } /** * Method __repr__ * * @return PyString * */ public PyString __repr__() { // care is taken not to display a rounded second value StringBuffer buf = new StringBuffer("<PyStatement object for ["); buf.append(__str__().toString()); buf.append("] at ").append(Py.id(this)).append(">"); return Py.newString(buf.toString()); } /** * Method toString * * @return String * */ public String toString() { return __repr__().toString(); } /** * Gets the value of the attribute name. * * @param name * @return the attribute for the given name */ public PyObject __findattr__(String name) { if ("style".equals(name)) { return Py.newInteger(style); } else if ("closed".equals(name)) { return Py.newBoolean(closed); } else if ("__statement__".equals(name)) { return Py.java2py(statement); } else if ("__methods__".equals(name)) { return __methods__; } else if ("__members__".equals(name)) { return __members__; } return super.__findattr__(name); } /** * Initializes the object's namespace. * * @param dict */ static public void classDictInit(PyObject dict) { dict.__setitem__("__version__", Py.newString("$Revision: 1.1 $").__getslice__(Py.newInteger(11), Py.newInteger(-2), null)); // hide from python dict.__setitem__("classDictInit", null); dict.__setitem__("statement", null); dict.__setitem__("params", null); dict.__setitem__("execute", null); dict.__setitem__("STATEMENT_STATIC", null); dict.__setitem__("STATEMENT_PREPARED", null); dict.__setitem__("STATEMENT_CALLABLE", null); } /** * Delete the statement. * */ public void __del__() { close(); } /** * Method execute * * @param cursor * * * @throws SQLException */ void execute(PyCursor cursor) throws SQLException { if (closed) { throw zxJDBC.makeException(zxJDBC.ProgrammingError, "statement is closed"); } Fetch fetch = cursor.fetch; switch (this.style) { case STATEMENT_STATIC : if (this.statement.execute((String)this.sql)) { fetch.add(this.statement.getResultSet()); } break; case STATEMENT_PREPARED : final PreparedStatement preparedStatement = (PreparedStatement)this.statement; if (preparedStatement.execute()) { fetch.add(preparedStatement.getResultSet()); } break; case STATEMENT_CALLABLE : final CallableStatement callableStatement = (CallableStatement)this.statement; if (callableStatement.execute()) { fetch.add(callableStatement.getResultSet()); } fetch.add(callableStatement, (Procedure)sql, params); break; default : throw zxJDBC.makeException(zxJDBC.ProgrammingError, zxJDBC.getString("invalidStyle")); } } /** * Method close * */ public void close() { try { this.statement.close(); } catch (SQLException e) { throw zxJDBC.makeException(e); } finally { this.closed = true; } } } Index: PyCursor.java =================================================================== RCS file: /cvsroot/jython/jython/com/ziclix/python/sql/PyCursor.java,v retrieving revision 1.21 retrieving revision 1.22 diff -C2 -d -r1.21 -r1.22 *** PyCursor.java 12 Apr 2002 20:32:45 -0000 1.21 --- PyCursor.java 19 Apr 2002 19:01:06 -0000 1.22 *************** *** 63,68 **** protected DataHandler datahandler; ! /** Field sqlStatement */ ! protected Statement sqlStatement; // they are stateless instances, so we only need to instantiate it once --- 63,68 ---- protected DataHandler datahandler; ! /** Field statement */ ! protected PyStatement statement; // they are stateless instances, so we only need to instantiate it once *************** *** 80,83 **** --- 80,85 ---- /** * Create the cursor with a static fetch. + * + * @param connection */ PyCursor(PyConnection connection) { *************** *** 88,91 **** --- 90,96 ---- * 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) { *************** *** 108,111 **** --- 113,121 ---- * 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) { *************** *** 149,153 **** m[8] = new PyString("write"); __methods__ = new PyList(m); ! m = new PyObject[9]; m[0] = new PyString("arraysize"); m[1] = new PyString("rowcount"); --- 159,163 ---- m[8] = new PyString("write"); __methods__ = new PyList(m); ! m = new PyObject[10]; m[0] = new PyString("arraysize"); m[1] = new PyString("rowcount"); *************** *** 159,162 **** --- 169,173 ---- m[7] = new PyString("updatecount"); m[8] = new PyString("softspace"); + m[9] = new PyString("closed"); __members__ = new PyList(m); } *************** *** 226,229 **** --- 237,242 ---- } else if ("connection".equals(name)) { return this.connection; + } else if ("closed".equals(name)) { + return Py.newBoolean(closed); } *************** *** 251,254 **** --- 264,268 ---- 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 *************** *** 258,263 **** dict.__setitem__("addWarning", null); dict.__setitem__("fetch", null); ! dict.__setitem__("closed", null); ! dict.__setitem__("sqlStatement", null); dict.__setitem__("dynamicFetch", null); dict.__setitem__("getPyClass", null); --- 272,276 ---- dict.__setitem__("addWarning", null); dict.__setitem__("fetch", null); ! dict.__setitem__("statement", null); dict.__setitem__("dynamicFetch", null); dict.__setitem__("getPyClass", null); *************** *** 267,286 **** /** - * An interface to allow the abstraction of SQL execution for - * different statements. - */ - private static interface ExecuteSQL { - - /** - * Execute a SQL statement and add the results to Fetch as - * appropriate. - * - * @throws SQLException - * - */ - public void executeSQL() throws SQLException; - } - - /** * Delete the cursor. * --- 280,283 ---- *************** *** 342,345 **** --- 339,344 ---- * * @since Jython 2.2 + * + * @return PyObject */ public PyObject __iternext__() { *************** *** 355,358 **** --- 354,358 ---- * @return DatabaseMetaData * + * @throws SQLException */ protected DatabaseMetaData getMetaData() throws SQLException { *************** *** 362,365 **** --- 362,367 ---- /** * Return the currently bound DataHandler. + * + * @return DataHandler */ public DataHandler getDataHandler() { *************** *** 370,402 **** * Prepare a statement ready for executing. * ! * @param sqlString the sql to execute * @param maxRows max number of rows to be returned * @param prepared if true, prepare the statement, otherwise create a normal statement ! * @throws SQLException */ ! protected void prepareStatement(String sqlString, PyObject maxRows, boolean prepared) throws SQLException { ! boolean normal = ((this.rsType == Py.None) && (this.rsConcur == Py.None)); ! if (normal) { ! if (prepared) { ! this.sqlStatement = this.connection.connection.prepareStatement(sqlString); } else { ! this.sqlStatement = this.connection.connection.createStatement(); } - } else { - int t = this.rsType.__int__().getValue(); - int c = this.rsConcur.__int__().getValue(); ! if (prepared) { ! this.sqlStatement = this.connection.connection.prepareStatement(sqlString, t, c); ! } else { ! this.sqlStatement = this.connection.connection.createStatement(t, c); } } ! if (maxRows != Py.None) { ! this.sqlStatement.setMaxRows(maxRows.__int__().getValue()); ! } } --- 372,434 ---- * 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 */ ! protected PyStatement prepareStatement(PyObject sql, PyObject maxRows, boolean prepared) { ! PyStatement stmt = null; ! if (sql == Py.None) { ! return null; ! } ! ! try { ! if (sql instanceof PyStatement) { ! stmt = (PyStatement)sql; } else { ! Statement sqlStatement = null; ! String sqlString = sql.__str__().toString(); ! ! if (sqlString.trim().length() == 0) { ! return null; ! } ! ! boolean normal = ((this.rsType == Py.None) && (this.rsConcur == Py.None)); ! ! if (normal) { ! if (prepared) { ! sqlStatement = this.connection.connection.prepareStatement(sqlString); ! } else { ! sqlStatement = this.connection.connection.createStatement(); ! } ! } else { ! int t = this.rsType.__int__().getValue(); ! int c = this.rsConcur.__int__().getValue(); ! ! if (prepared) { ! sqlStatement = this.connection.connection.prepareStatement(sqlString, t, c); ! } else { ! sqlStatement = this.connection.connection.createStatement(t, c); ! } ! } ! ! int style = prepared ? PyStatement.STATEMENT_PREPARED : PyStatement.STATEMENT_STATIC; ! ! stmt = new PyStatement(sqlStatement, sqlString, style); } ! if (maxRows != Py.None) { ! stmt.statement.setMaxRows(maxRows.__int__().getValue()); } + } catch (PyException e) { + throw e; + } catch (Exception e) { + throw zxJDBC.makeException(e); } ! return stmt; } *************** *** 411,418 **** * The procedure may also provide a result set as output. This must then be made available * through the standard fetchXXX() methods. */ public void callproc(PyObject name, final PyObject params, PyObject bindings, PyObject maxRows) { ! clear(); try { --- 443,455 ---- * 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(); try { *************** *** 423,435 **** final Procedure procedure = new Procedure(this, name); ! PyDictionary callableBindings = new PyDictionary(); ! ! this.sqlStatement = procedure.prepareCall(this.rsType, this.rsConcur); if (maxRows != Py.None) { ! this.sqlStatement.setMaxRows(maxRows.__int__().getValue()); } // get the bindings per the stored proc spec procedure.normalizeInput(params, callableBindings); --- 460,472 ---- final Procedure procedure = new Procedure(this, name); ! Statement stmt = procedure.prepareCall(this.rsType, this.rsConcur); if (maxRows != Py.None) { ! stmt.setMaxRows(maxRows.__int__().getValue()); } // get the bindings per the stored proc spec + PyDictionary callableBindings = new PyDictionary(); + procedure.normalizeInput(params, callableBindings); *************** *** 439,459 **** } // prepare the statement prepare(params, callableBindings, procedure); ! ! // call the procedure ! execute(new ExecuteSQL() { ! ! public void executeSQL() throws SQLException { ! ! final CallableStatement callableStatement = (CallableStatement)sqlStatement; ! ! if (callableStatement.execute()) { ! fetch.add(callableStatement.getResultSet()); ! } ! ! fetch.add(callableStatement, procedure, params); ! } ! }); } else { throw zxJDBC.makeException(zxJDBC.NotSupportedError, zxJDBC.getString("noStoredProc")); --- 476,484 ---- } + this.statement = new PyStatement(stmt, procedure, params); + // prepare the statement prepare(params, callableBindings, procedure); ! this.statement.execute(this); } else { throw zxJDBC.makeException(zxJDBC.NotSupportedError, zxJDBC.getString("noStoredProc")); *************** *** 463,466 **** --- 488,497 ---- } catch (Exception e) { throw zxJDBC.makeException(e); + } finally { + if (this.statement != null) { + + // close what we opened + this.statement.close(); + } } } *************** *** 476,479 **** --- 507,515 ---- * * Return values are not defined. + * + * @param sql + * @param params + * @param bindings + * @param maxRows */ public void executemany(PyObject sql, PyObject params, PyObject bindings, PyObject maxRows) { *************** *** 506,510 **** * Return values are not defined. * ! * @param sql sql string * @param params params for a prepared statement * @param bindings dictionary of (param index : SQLType binding) --- 542,546 ---- * 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) *************** *** 513,543 **** public void execute(final PyObject sql, PyObject params, PyObject bindings, PyObject maxRows) { ! if (sql == Py.None) { ! return; ! } ! final String sqlString = sql.__str__().toString(); ! if (sqlString.trim().length() == 0) { return; } ! clear(); ! ! boolean hasParams = hasParams(params); try { - prepareStatement(sqlString, maxRows, hasParams); - if (hasParams) { - ExecuteSQL esql = new ExecuteSQL() { - - public void executeSQL() throws SQLException { - - if (((PreparedStatement)sqlStatement).execute()) { - fetch.add(sqlStatement.getResultSet()); - } - } - }; // if we have a sequence of sequences, let's run through them and finish --- 549,565 ---- public void execute(final PyObject sql, PyObject params, PyObject bindings, PyObject maxRows) { ! this.clear(); ! boolean hasParams = hasParams(params); ! PyStatement stmt = prepareStatement(sql, maxRows, hasParams); ! if (stmt == null) { return; } ! this.statement = stmt; try { if (hasParams) { // if we have a sequence of sequences, let's run through them and finish *************** *** 549,570 **** prepare(param, bindings, null); ! execute(esql); } } else { prepare(params, bindings, null); ! execute(esql); } } else { // execute the sql string straight up ! execute(new ExecuteSQL() { ! ! public void executeSQL() throws SQLException { ! ! if (sqlStatement.execute(sqlString)) { ! fetch.add(sqlStatement.getResultSet()); ! } ! } ! }); } } catch (PyException e) { --- 571,584 ---- prepare(param, bindings, null); ! execute(); } } else { prepare(params, bindings, null); ! execute(); } } else { // execute the sql string straight up ! execute(); } } catch (PyException e) { *************** *** 572,575 **** --- 586,597 ---- } catch (Exception e) { throw zxJDBC.makeException(e); + } finally { + if (this.statement != null) { + + // only close static, single-use statements + if (!(sql instanceof PyStatement) && (!this.dynamicFetch)) { + this.statement.close(); + } + } } } *************** *** 578,602 **** * Execute the current sql statement. Some generic functionality such * as updating the lastrowid and updatecount occur as well. - * - * @param ExecuteSQL execute - * - * @throws SQLException - * */ ! protected void execute(ExecuteSQL execute) throws SQLException { ! this.datahandler.preExecute(this.sqlStatement); ! // this performs the SQL execution and fetch per the Statement type ! execute.executeSQL(); ! this.lastrowid = this.datahandler.getRowId(this.sqlStatement); ! int uc = this.sqlStatement.getUpdateCount(); ! this.updatecount = (uc < 0) ? Py.None : Py.newInteger(uc); ! addWarning(this.sqlStatement.getWarnings()); ! this.datahandler.postExecute(this.sqlStatement); } --- 600,627 ---- * Execute the current sql statement. Some generic functionality such * as updating the lastrowid and updatecount occur as well. */ ! protected void execute() { ! try { ! Statement stmt = this.statement.statement; ! this.datahandler.preExecute(stmt); ! // this performs the SQL execution and fetch per the Statement type ! this.statement.execute(this); ! this.lastrowid = this.datahandler.getRowId(stmt); ! int uc = stmt.getUpdateCount(); ! this.updatecount = (uc < 0) ? Py.None : Py.newInteger(uc); ! ! addWarning(stmt.getWarnings()); ! this.datahandler.postExecute(stmt); ! } catch (PyException e) { ! throw e; ! } catch (Exception e) { ! throw zxJDBC.makeException(e); ! } } *************** *** 604,610 **** * Properly prepare the parameters of a prepared statement. * ! * @param PyObject params a non-None seq of sequences or entities ! * @param PyObject bindings an optional dictionary of index:DBApiType mappings ! * @param Procedure procedure * * @throws SQLException --- 629,635 ---- * Properly prepare the parameters of a prepared statement. * ! * @param params ! * @param bindings ! * @param procedure * * @throws SQLException *************** *** 618,622 **** // [3, 4] or (3, 4) ! final PreparedStatement preparedStatement = (PreparedStatement)this.sqlStatement; int columns = 0, column = 0, index = params.__len__(); --- 643,647 ---- // [3, 4] or (3, 4) ! final PreparedStatement preparedStatement = (PreparedStatement)this.statement.statement; int columns = 0, column = 0, index = params.__len__(); *************** *** 711,714 **** --- 736,741 ---- * from one fetchmany() call to the next. * + * + * @param size * @return a sequence of sequences from the result set, or None when no more data is available */ *************** *** 744,749 **** * database (e.g. backward scrolling). * ! * @param int value ! * @param String mode * */ --- 771,777 ---- * database (e.g. backward scrolling). * ! * ! * @param value ! * @param mode * */ *************** *** 754,757 **** --- 782,787 ---- /** * Adds a warning to the tuple and will follow the chain as necessary. + * + * @param warning */ protected void addWarning(SQLWarning warning) { *************** *** 792,798 **** if (closed) { ! throw zxJDBC.makeException(zxJDBC.InternalError, "cursor is closed"); } this.warnings = Py.None; this.lastrowid = Py.None; --- 822,829 ---- if (closed) { ! throw zxJDBC.makeException(zxJDBC.ProgrammingError, "cursor is closed"); } + this.statement = null; this.warnings = Py.None; this.lastrowid = Py.None; *************** *** 805,815 **** this.fetch = Fetch.newFetch(this); } - - try { - this.sqlStatement.close(); - } catch (Exception e) {} - finally { - this.sqlStatement = null; - } } --- 836,839 ---- *************** *** 817,821 **** * Method isSeq * ! * @param PyObject object * * @return true for any PyList, PyTuple or java.util.List --- 841,846 ---- * Method isSeq * ! * ! * @param object * * @return true for any PyList, PyTuple or java.util.List *************** *** 840,844 **** * Method hasParams * ! * @param PyObject params * * @return boolean --- 865,870 ---- * Method hasParams * ! * ! * @param params * * @return boolean *************** *** 864,868 **** * Method isSeqSeq * ! * @param PyObject object * * @return true is a sequence of sequences --- 890,895 ---- * Method isSeqSeq * ! * ! * @param object * * @return true is a sequence of sequences *************** *** 899,906 **** * Constructor CursorFunc * ! * @param String name ! * @param int index ! * @param int argcount ! * @param String doc * */ --- 926,934 ---- * Constructor CursorFunc * ! * ! * @param name ! * @param index ! * @param argcount ! * @param doc * */ *************** *** 912,920 **** * Constructor CursorFunc * ! * @param String name ! * @param int index ! * @param int minargs ! * @param int maxargs ! * @param String doc * */ --- 940,949 ---- * Constructor CursorFunc * ! * ! * @param name ! * @param index ! * @param minargs ! * @param maxargs ! * @param doc * */ *************** *** 960,964 **** * Method __call__ * ! * @param PyObject arg * * @return PyObject --- 989,994 ---- * Method __call__ * ! * ! * @param arg * * @return PyObject *************** *** 1003,1006 **** --- 1033,1039 ---- return Py.None; + case 12 : + return cursor.prepareStatement(arg, Py.None, true); + default : throw argCountError(1); *************** *** 1011,1016 **** * Method __call__ * ! * @param PyObject arga ! * @param PyObject argb * * @return PyObject --- 1044,1050 ---- * Method __call__ * ! * ! * @param arga ! * @param argb * * @return PyObject *************** *** 1054,1060 **** * Method __call__ * ! * @param PyObject arga ! * @param PyObject argb ! * @param PyObject argc * * @return PyObject --- 1088,1095 ---- * Method __call__ * ! * ! * @param arga ! * @param argb ! * @param argc * * @return PyObject *************** *** 1090,1095 **** * Method __call__ * ! * @param PyObject[] args ! * @param String[] keywords * * @return PyObject --- 1125,1131 ---- * Method __call__ * ! * ! * @param args ! * @param keywords * * @return PyObject Index: PyConnection.java =================================================================== RCS file: /cvsroot/jython/jython/com/ziclix/python/sql/PyConnection.java,v retrieving revision 1.7 retrieving revision 1.8 diff -C2 -d -r1.7 -r1.8 *** PyConnection.java 12 Apr 2002 04:12:27 -0000 1.7 --- PyConnection.java 19 Apr 2002 19:01:06 -0000 1.8 *************** *** 24,27 **** --- 24,30 ---- public class PyConnection extends PyObject implements ClassDictInit { + /** Field closed */ + protected boolean closed; + /** Field connection */ protected Connection connection; *************** *** 61,65 **** m[4] = new PyString("nativesql"); __methods__ = new PyList(m); ! m = new PyObject[7]; m[0] = new PyString("autocommit"); m[1] = new PyString("dbname"); --- 64,68 ---- m[4] = new PyString("nativesql"); __methods__ = new PyList(m); ! m = new PyObject[8]; m[0] = new PyString("autocommit"); m[1] = new PyString("dbname"); *************** *** 69,72 **** --- 72,76 ---- m[5] = new PyString("__connection__"); m[6] = new PyString("__cursors__"); + m[7] = new PyString("closed"); __members__ = new PyList(m); } *************** *** 74,80 **** --- 78,89 ---- /** * Create a PyConnection with the open connection. + * + * @param connection + * + * @throws SQLException */ public PyConnection(Connection connection) throws SQLException { + this.closed = false; this.connection = connection; this.cursors = new LinkedList(); *************** *** 103,107 **** * Method classDictInit * ! * @param PyObject dict * */ --- 112,117 ---- * Method classDictInit * ! * ! * @param dict * */ *************** *** 195,198 **** --- 205,210 ---- } else if ("__members__".equals(name)) { return __members__; + } else if ("closed".equals(name)) { + return Py.newBoolean(closed); } *************** *** 210,213 **** --- 222,229 ---- public void close() { + if (closed) { + return; + } + synchronized (this.cursors) { *************** *** 224,227 **** --- 240,245 ---- } catch (SQLException e) { throw zxJDBC.makeException(e); + } finally { + this.closed = true; } } *************** *** 238,241 **** --- 256,263 ---- public void commit() { + if (closed) { + throw zxJDBC.makeException(zxJDBC.ProgrammingError, "connection is closed"); + } + if (!this.supportsTransactions) { return; *************** *** 261,264 **** --- 283,290 ---- public void rollback() { + if (closed) { + throw zxJDBC.makeException(zxJDBC.ProgrammingError, "connection is closed"); + } + if (!this.supportsTransactions) { return; *************** *** 278,282 **** * that the driver would have sent. * ! * @param PyObject a SQL statement that may contain one or more '?' parameter placeholders * * @return the native form of this statement --- 304,309 ---- * that the driver would have sent. * ! * ! * @param nativeSQL * * @return the native form of this statement *************** *** 285,288 **** --- 312,319 ---- public PyObject nativesql(PyObject nativeSQL) { + if (closed) { + throw zxJDBC.makeException(zxJDBC.ProgrammingError, "connection is closed"); + } + if (nativeSQL == Py.None) { return Py.None; *************** *** 333,336 **** --- 364,371 ---- public PyCursor cursor(boolean dynamicFetch, PyObject rsType, PyObject rsConcur) { + if (closed) { + throw zxJDBC.makeException(zxJDBC.ProgrammingError, "connection is closed"); + } + PyCursor cursor = new PyExtendedCursor(this, dynamicFetch, rsType, rsConcur); *************** *** 343,347 **** * Unregister an open PyCursor. * ! * @param PyCursor cursor * */ --- 378,383 ---- * Unregister an open PyCursor. * ! * ! * @param cursor * */ *************** *** 365,373 **** * Constructor ConnectionFunc * ! * @param String name ! * @param int index ! * @param int minargs ! * @param int maxargs ! * @param String doc * */ --- 401,410 ---- * Constructor ConnectionFunc * ! * ! * @param name ! * @param index ! * @param minargs ! * @param maxargs ! * @param doc * */ *************** *** 414,418 **** * Method __call__ * ! * @param PyObject arg * * @return PyObject --- 451,456 ---- * Method __call__ * ! * ! * @param arg * * @return PyObject *************** *** 439,444 **** * Method __call__ * ! * @param PyObject arg1 ! * @param PyObject arg2 * * @return PyObject --- 477,483 ---- * Method __call__ * ! * ! * @param arg1 ! * @param arg2 * * @return PyObject *************** *** 461,467 **** * Method __call__ * ! * @param PyObject arg1 ! * @param PyObject arg2 ! * @param PyObject arg3 * * @return PyObject --- 500,507 ---- * Method __call__ * ! * ! * @param arg1 ! * @param arg2 ! * @param arg3 * * @return PyObject *************** *** 485,490 **** * Method __call__ * ! * @param PyObject[] args ! * @param String[] keywords * * @return PyObject --- 525,531 ---- * Method __call__ * ! * ! * @param args ! * @param keywords * * @return PyObject |