From: brian z. <bz...@us...> - 2001-11-20 04:55:21
|
Update of /cvsroot/jython/jython/com/ziclix/python/sql In directory usw-pr-cvs1:/tmp/cvs-serv7094/com/ziclix/python/sql Added Files: JDBC20DataHandler.java PyCursor.java PyConnection.java PyExtendedCursor.java zxJDBC.java DataHandler.java Fetch.java FilterDataHandler.java Log Message: initial zxJDBC checkin --- NEW FILE: JDBC20DataHandler.java --- /* * Jython Database Specification API 2.0 * * $Id: JDBC20DataHandler.java,v 1.1 2001/11/20 04:55:18 bzimmer Exp $ * * Copyright (c) 2001 brian zimmer <bz...@zi...> * */ package com.ziclix.python.sql; import java.io.*; import java.sql.*; import java.math.*; import org.python.core.*; /** * Support for JDBC 2.x type mappings, including Arrays, CLOBs and BLOBs. * * @author brian zimmer * @author last revised by $Author: bzimmer $ * @version $Revision: 1.1 $ */ public class JDBC20DataHandler extends FilterDataHandler { /** * Handle JDBC 2.0 datatypes. * */ public JDBC20DataHandler(DataHandler datahandler) { super(datahandler); } /** * Handle CLOBs and BLOBs. * * @param stmt * @param index * @param object * @param type * @throws SQLException */ public void setJDBCObject(PreparedStatement stmt, int index, PyObject object, int type) throws SQLException { if (DataHandler.checkNull(stmt, index, object, type)) { return; } switch (type) { case Types.CLOB : if (object instanceof PyFile) { object = ((PyFile)object).read(); } String clob = (String)object.__tojava__(String.class); int length = clob.length(); InputStream stream = new ByteArrayInputStream(clob.getBytes()); stream = new BufferedInputStream(stream); stmt.setBinaryStream(index, stream, length); // Reader reader = new StringReader(clob); // reader = new BufferedReader(reader); // stmt.setCharacterStream(index, reader, length); break; case Types.BLOB : byte[] lob = null; Object jobject = null; if (object instanceof PyFile) { jobject = object.__tojava__(InputStream.class); } else { jobject = object.__tojava__(Object.class); } // it really is unfortunate that I need to send the length of the stream if (jobject instanceof InputStream) { lob = DataHandler.read(new BufferedInputStream((InputStream)jobject)); } else if (jobject instanceof byte[]) { lob = (byte[])jobject; } if (lob != null) { stmt.setBytes(index, lob); break; } default : super.setJDBCObject(stmt, index, object, type); break; } } /** * Get the object from the result set. * * @param set * @param col * @param type * @return a Python object * @throws SQLException */ public PyObject getPyObject(ResultSet set, int col, int type) throws SQLException { PyObject obj = Py.None; switch (type) { case Types.NUMERIC : case Types.DECIMAL : // in JDBC 2.0, use of a scale is deprecated BigDecimal bd = set.getBigDecimal(col); obj = (bd == null) ? Py.None : Py.newFloat(bd.doubleValue()); break; case Types.CLOB : /* * It seems some drivers (well at least Informix) don't clean up after themselves * if the Clob is requested. The engine keeps a handle to an open table for each * row requested and cleans up fully only when the ResultSet or Connection is closed. * While this generally will never be noticed because the number of CLOBs or BLOBs * queried will likely be small in the event a large number are queried, it is a huge * problem. So, handle it as low as possible by managing the stream directly. I've * decided to leave this in the generic JDBC20 handler because it works for all engines * I've tested and seems to perform quite well to boot. */ Reader reader = null; try { InputStream stream = set.getBinaryStream(col); if (stream == null) { obj = Py.None; } else { reader = new InputStreamReader(stream); reader = new BufferedReader(reader); obj = Py.newString(DataHandler.read(reader)); } } finally { if (reader != null) { try { reader.close(); } catch (Exception e) {} } } break; case Types.BLOB : Blob blob = set.getBlob(col); if (blob == null) { obj = Py.None; } else { InputStream stream = null; try { stream = blob.getBinaryStream(); stream = new BufferedInputStream(stream); obj = Py.java2py(DataHandler.read(stream)); } finally { if (stream != null) { try { stream.close(); } catch (Exception e) {} } } } break; case Types.ARRAY : obj = Py.java2py(set.getArray(col).getArray()); break; default : return super.getPyObject(set, col, type); } return (set.wasNull() || (obj == null)) ? Py.None : obj; } } --- NEW FILE: PyCursor.java --- /* * Jython Database Specification API 2.0 * * $Id: PyCursor.java,v 1.1 2001/11/20 04:55:18 bzimmer Exp $ * * Copyright (c) 2001 brian zimmer <bz...@zi...> * */ package com.ziclix.python.sql; import java.io.*; import java.sql.*; import java.math.*; import java.util.*; import org.python.core.*; import com.ziclix.python.sql.util.*; /** * These objects represent a database cursor, which is used to manage the * context of a fetch operation. * * @author brian zimmer * @author last revised by $Author: bzimmer $ * @version $Revision: 1.1 $ */ public class PyCursor extends PyObject implements ClassDictInit { /** Field fetch */ protected Fetch fetch; /** Field arraysize */ protected int arraysize; /** Field warnings */ protected PyObject warnings; /** Field dynamicFetch */ protected boolean dynamicFetch; /** Field connection */ protected Connection connection; /** Field datahandler */ protected DataHandler datahandler; /** Field sqlStatement */ protected PreparedStatement sqlStatement; // they are stateless instances, so we only need to instantiate it once private static DataHandler DATAHANDLER = null; // discern the correct datahandler static { DATAHANDLER = new DataHandler(); try { DATAHANDLER = new JDBC20DataHandler(DATAHANDLER); } catch (Exception e) {} } /** * Create the cursor with a static fetch. */ PyCursor(Connection 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. */ PyCursor(Connection connection, boolean dynamicFetch) { this.arraysize = 1; this.connection = connection; this.datahandler = DATAHANDLER; this.dynamicFetch = dynamicFetch; // constructs the appropriate Fetch among other things this.clear(); } /** 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[7]; 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"); __methods__ = new PyList(m); m = new PyObject[5]; m[0] = new PyString("arraysize"); m[1] = new PyString("rowcount"); m[2] = new PyString("description"); m[3] = new PyString("datahandler"); m[4] = new PyString("warnings"); __members__ = new PyList(m); } /** * String representation of the object. * * @return a string representation of the object. */ public String toString() { return "<PyCursor object instance at " + hashCode() + ">"; } /** * Sets the attribute name to value. * * @param name * @param value */ public void __setattr__(String name, PyObject value) { if ("arraysize".equals(name)) { arraysize = ((PyInteger)value).getValue(); } else if ("datahandler".equals(name)) { this.datahandler = (DataHandler)value.__tojava__(DataHandler.class); } else { super.__setattr__(name, value); } } /** * Gets the value of the attribute name. * * @param name * @return the attribute for the given name */ public PyObject __findattr__(String name) { if ("arraysize".equals(name)) { return new PyInteger(arraysize); } else if ("__methods__".equals(name)) { return __methods__; } else if ("__members__".equals(name)) { return __members__; } else if ("description".equals(name)) { return this.fetch.getDescription(); } else if ("rowcount".equals(name)) { return new PyInteger(this.fetch.getRowCount()); } else if ("warnings".equals(name)) { return warnings; } else if ("datahandler".equals(name)) { return Py.java2py(this.datahandler); } else if ("dynamic".equals(name)) { return this.dynamicFetch ? Py.One : Py.Zero; } 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)); dict.__setitem__("fetchmany", new CursorFunc("fetchmany", 0, 1, 2, "fetch specified number of rows")); dict.__setitem__("close", new CursorFunc("close", 1, 1, "close the cursor")); dict.__setitem__("fetchall", new CursorFunc("fetchall", 2, 1, "fetch all results")); dict.__setitem__("fetchone", new CursorFunc("fetchone", 3, 1, "fetch the next result")); dict.__setitem__("nextset", new CursorFunc("nextset", 4, 1, "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, 2, "executes a stored procedure")); dict.__setitem__("executemany", new CursorFunc("executemany", 9, 1, 3, "execute sql with the parameter list")); // hide from python dict.__setitem__("classDictInit", null); dict.__setitem__("toString", null); dict.__setitem__("connection", null); dict.__setitem__("getDataHandler", null); dict.__setitem__("addWarning", null); dict.__setitem__("fetch", null); dict.__setitem__("newFetch", null); dict.__setitem__("sqlStatement", null); dict.__setitem__("dynamicFetch", null); dict.__setitem__("getPyClass", 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() { this.clear(); } /** * Return the currently bound DataHandler. */ public DataHandler getDataHandler() { return this.datahandler; } /** * Method newFetch * */ protected void newFetch() { if (this.dynamicFetch) { this.fetch = Fetch.newDynamicFetch(this); } else { this.fetch = Fetch.newStaticFetch(this); } } /** * Prepare a callable statement (stored procedure). * * @param sqlString * @throws SQLException */ protected void callableStatement(String sqlString) throws SQLException { this.sqlStatement = this.connection.prepareCall(sqlString); } /** * Prepare a statement ready for executing. * * @param sqlString * @param maxRows max number of rows to be returned * @throws SQLException */ protected void prepareStatement(String sqlString, PyObject maxRows) throws SQLException { int maxrows = 0; if (!maxRows.equals(Py.None)) { maxrows = ((Integer)maxRows.__tojava__(Integer.class)).intValue(); } this.sqlStatement = this.connection.prepareStatement(sqlString); this.sqlStatement.setMaxRows(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. */ public void callproc(String sqlString, PyObject params) { clear(); try { if (this.connection.getMetaData().supportsStoredProcedures()) { callableStatement(sqlString); execute(params, Py.None); } else { throw zxJDBC.makeException(zxJDBC.NotSupportedError, zxJDBC.getString("noStoredProc")); } } catch (PyException e) { throw e; } catch (Exception e) { throw zxJDBC.newError(e); } } /** * 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. */ public void executemany(String sqlString, PyObject params, PyObject bindings) { execute(sqlString, params, bindings, Py.Zero); } /** * 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 sqlString sql string * @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(String sqlString, PyObject params, PyObject bindings, PyObject maxRows) { clear(); try { prepareStatement(sqlString, maxRows); execute(params, bindings); } catch (PyException e) { throw e; } catch (Exception e) { throw zxJDBC.newError(e); } } /** * Perform the execution of a statement. */ protected void execute(PyObject params, PyObject bindings) throws SQLException { boolean seq = isSeq(params); // the optional argument better be a sequence if (!seq && (Py.None != params)) { throw zxJDBC.makeException(zxJDBC.ProgrammingError, zxJDBC.getString("optionalSecond")); } boolean hasParams = (seq && (params.__len__() > 0)); // if we have a sequence of sequences, let's run through them and finish if (hasParams && isSeqSeq(params)) { for (int i = 0; i < params.__len__(); i++) { PyObject param = params.__getitem__(i); // [(3, 4)] or [(3, 4), (5, 6)] execute(param, bindings); } // we've recursed through everything, so we're done return; } if (hasParams) { // clear the statement so all new bindings take affect this.sqlStatement.clearParameters(); // [3, 4] or (3, 4) Integer binding = null; PyObject param = Py.None, index = Py.None; for (int i = 0; i < params.__len__(); i++) { binding = null; index = Py.newInteger(i); param = params.__getitem__(i); if (bindings != Py.None) { PyObject tmp = bindings.__finditem__(index); if (tmp != null) { try { binding = (Integer)tmp.__tojava__(Integer.class); } catch (ClassCastException e) { throw zxJDBC.makeException(zxJDBC.ProgrammingError, zxJDBC.getString("bindingValue")); } } } if (binding == null) { this.datahandler.setJDBCObject(this.sqlStatement, i + 1, param); } else { this.datahandler.setJDBCObject(this.sqlStatement, i + 1, param, binding.intValue()); } } } this.datahandler.preExecute(this.sqlStatement); this.sqlStatement.execute(); create(this.sqlStatement.getResultSet()); this.datahandler.postExecute(this.sqlStatement); addWarning(this.sqlStatement.getWarnings()); return; } /** * 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(); } /** * 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 None when no more data is available */ public PyObject fetchall() { return this.fetch.fetchall(); } /** * 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. * * @return a sequence of sequences from the result set, or None when no more data is available */ public PyObject fetchmany(int size) { return this.fetch.fetchmany(size); } /** * 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(); } /** * Create the results after a successful execution and closes the result set. * * @param rs A ResultSet. */ protected void create(ResultSet rs) { create(rs, null); } /** * Create the results after a successful execution and closes the result set. * Optionally takes a set of JDBC-indexed columns to automatically set to None * primarily to support getTypeInfo() which sets a column type of a number but * doesn't use the value so a driver is free to put anything it wants there. * * @param rs A ResultSet. * @param skipCols set of JDBC-indexed columns to automatically set as None */ protected void create(ResultSet rs, Set skipCols) { this.fetch.add(rs, skipCols); } /** * Adds a warning to the tuple and will follow the chain as necessary. */ void addWarning(SQLWarning warning) { if (warning == null) { return; } if (this.warnings == Py.None) { this.warnings = new PyList(); } PyTuple warn = new PyTuple(); // there are three parts: (reason, state, vendorCode) warn.__add__(Py.java2py(warning.getMessage())); warn.__add__(Py.java2py(warning.getSQLState())); warn.__add__(Py.newInteger(warning.getErrorCode())); // add the warning to the list ((PyList)this.warnings).append(warn); SQLWarning next = warning.getNextWarning(); if (next != null) { addWarning(next); } return; } /** * Reset the cursor state. */ protected void clear() { this.warnings = Py.None; try { this.fetch.close(); } catch (Exception e) {} finally { this.newFetch(); } try { this.sqlStatement.close(); } catch (Exception e) {} finally { this.sqlStatement = null; } } /** * @return true for any PyList, PyTuple or java.util.List */ protected boolean isSeq(PyObject object) { if ((object == null) || (object == Py.None)) { return false; } if (object.__tojava__(List.class) != Py.NoConversion) { return true; } // 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 true for any PyList, PyTuple or java.util.List of PyLists, PyTuples or java.util.Lists */ protected 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 * * @author * @date $today.date$ * @author last modified by $Author: bzimmer $ * @date last modified on $Date: 2001/11/20 04:55:18 $ * @version $Revision: 1.1 $ * @copyright 2001 brian zimmer */ class CursorFunc extends PyBuiltinFunctionSet { /** * Constructor CursorFunc * * @param String name * @param int index * @param int argcount * @param String doc * */ CursorFunc(String name, int index, int argcount, String doc) { super(name, index, argcount, argcount, true, doc); } /** * Constructor CursorFunc * * @param String name * @param int index * @param int minargs * @param int maxargs * @param String doc * */ CursorFunc(String name, int index, int minargs, int maxargs, String doc) { super(name, index, minargs, maxargs, true, doc); } /** * Method __call__ * * @return PyObject * */ 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 argCountError(0); } } /** * Method __call__ * * @param PyObject arg * * @return PyObject * */ public PyObject __call__(PyObject arg) { PyCursor cursor = (PyCursor)__self__; switch (index) { case 0 : return cursor.fetchmany(((PyInteger)arg).getValue()); case 5 : cursor.execute((String)arg.__tojava__(String.class), Py.None, Py.None, Py.None); return Py.None; case 6 : case 7 : return Py.None; case 8 : cursor.callproc((String)arg.__tojava__(String.class), Py.None); return Py.None; case 9 : cursor.executemany((String)arg.__tojava__(String.class), Py.None, Py.None); return Py.None; default : throw argCountError(1); } } /** * Method __call__ * * @param PyObject arga * @param PyObject argb * * @return PyObject * */ public PyObject __call__(PyObject arga, PyObject argb) { PyCursor cursor = (PyCursor)__self__; switch (index) { case 5 : cursor.execute((String)arga.__tojava__(String.class), argb, Py.None, Py.None); return Py.None; case 7 : return Py.None; case 8 : cursor.callproc((String)arga.__tojava__(String.class), argb); return Py.None; case 9 : cursor.executemany((String)arga.__tojava__(String.class), argb, Py.None); return Py.None; default : throw argCountError(2); } } /** * Method __call__ * * @param PyObject arga * @param PyObject argb * @param PyObject argc * * @return PyObject * */ public PyObject __call__(PyObject arga, PyObject argb, PyObject argc) { PyCursor cursor = (PyCursor)__self__; switch (index) { case 5 : cursor.execute((String)arga.__tojava__(String.class), argb, argc, Py.None); return Py.None; case 9 : cursor.executemany((String)arga.__tojava__(String.class), argb, argc); return Py.None; default : throw argCountError(3); } } /** * Method __call__ * * @param PyObject[] args * @param String[] keywords * * @return PyObject * */ public PyObject __call__(PyObject[] args, String[] keywords) { PyCursor cursor = (PyCursor)__self__; switch (index) { case 5 : PyArgParser parser = new PyArgParser(args, keywords); String sql = (String)parser.arg(0).__tojava__(String.class); PyObject params = parser.kw("params", Py.None); PyObject bindings = parser.kw("bindings", Py.None); PyObject maxrows = parser.kw("maxrows", Py.None); params = (parser.numArg() >= 2) ? parser.arg(1) : params; bindings = (parser.numArg() >= 3) ? parser.arg(2) : bindings; maxrows = (parser.numArg() >= 4) ? parser.arg(3) : maxrows; cursor.execute(sql, params, bindings, maxrows); return Py.None; default : throw argCountError(4); } } } --- NEW FILE: PyConnection.java --- /* * Jython Database Specification API 2.0 * * $Id: PyConnection.java,v 1.1 2001/11/20 04:55:18 bzimmer Exp $ * * Copyright (c) 2001 brian zimmer <bz...@zi...> * */ package com.ziclix.python.sql; import java.sql.*; import org.python.core.*; /** * A connection to the database. * * @author brian zimmer * @author last revised by $Author: bzimmer $ * @version $Revision: 1.1 $ */ public class PyConnection extends PyObject implements ClassDictInit { /** Field connection */ protected Connection connection; /** Field supportsTransactions */ protected boolean supportsTransactions; /** Field __class__ */ public static PyClass __class__; /** * Method getPyClass * * @return PyClass * */ protected PyClass getPyClass() { return __class__; } /** * Create a PyConnection with the open connection. */ public PyConnection(Connection connection) throws SQLException { this.connection = connection; this.supportsTransactions = this.connection.getMetaData().supportsTransactions(); if (this.supportsTransactions) { this.connection.setAutoCommit(false); } } /** * Produces a string representation of the object. * * @return string representation of the object. */ public String toString() { try { return "<PyConnection user='" + this.connection.getMetaData().getUserName() + "', url='" + this.connection.getMetaData().getURL() + "'>"; } catch (SQLException e) { return "<PyConnection at " + hashCode() + ">"; } } /** * Method classDictInit * * @param PyObject dict * */ static public void classDictInit(PyObject dict) { dict.__setitem__("autocommit", new PyInteger(0)); dict.__setitem__("__version__", Py.newString("$Revision: 1.1 $").__getslice__(Py.newInteger(11), Py.newInteger(-2), null)); dict.__setitem__("close", new ConnectionFunc("close", 0, 0, 0, zxJDBC.getString("close"))); dict.__setitem__("commit", new ConnectionFunc("commit", 1, 0, 0, zxJDBC.getString("commit"))); dict.__setitem__("cursor", new ConnectionFunc("cursor", 2, 0, 1, zxJDBC.getString("cursor"))); dict.__setitem__("rollback", new ConnectionFunc("rollback", 3, 0, 0, zxJDBC.getString("rollback"))); // hide from python dict.__setitem__("initModule", null); dict.__setitem__("toString", null); dict.__setitem__("setConnection", null); dict.__setitem__("getPyClass", null); dict.__setitem__("connection", null); dict.__setitem__("classDictInit", null); } /** * Sets the attribute. * * @param name * @param value */ public void __setattr__(String name, PyObject value) { if ("autocommit".equals(name)) { try { if (this.supportsTransactions) { this.connection.setAutoCommit(value.__nonzero__()); } } catch (SQLException e) { throw zxJDBC.makeException(zxJDBC.DatabaseError, e.getMessage()); } return; } super.__setattr__(name, value); } /** * Finds the attribute. * * @param name the name of the attribute of interest * @return the value for the attribute of the specified name */ public PyObject __findattr__(String name) { if ("autocommit".equals(name)) { try { return connection.getAutoCommit() ? Py.One : Py.Zero; } catch (SQLException e) { throw zxJDBC.makeException(zxJDBC.DatabaseError, e.getMessage()); } } else if ("dbname".equals(name)) { try { return Py.newString(this.connection.getMetaData().getDatabaseProductName()); } catch (SQLException e) { throw zxJDBC.makeException(zxJDBC.DatabaseError, e.getMessage()); } } else if ("dbversion".equals(name)) { try { return Py.newString(this.connection.getMetaData().getDatabaseProductVersion()); } catch (SQLException e) { throw zxJDBC.makeException(zxJDBC.DatabaseError, e.getMessage()); } } else if ("driverversion".equals(name)) { try { return Py.newString(this.connection.getMetaData().getDriverVersion()); } catch (SQLException e) { throw zxJDBC.makeException(zxJDBC.DatabaseError, e.getMessage()); } } else if ("url".equals(name)) { try { return Py.newString(this.connection.getMetaData().getURL()); } catch (SQLException e) { throw zxJDBC.makeException(zxJDBC.DatabaseError, e.getMessage()); } } else if ("__connection__".equals(name)) { return Py.java2py(this.connection); } return super.__findattr__(name); } /** * Close the connection now (rather than whenever __del__ is called). * The connection will be unusable from this point forward; an Error * (or subclass) exception will be raised if any operation is attempted * with the connection. The same applies to all cursor objects trying * to use the connection. * */ public void close() { try { // close the cursors too? this.connection.close(); } catch (SQLException e) { throw zxJDBC.newError(e); } } /** * Commit any pending transaction to the database. Note that if the * database supports an auto-commit feature, this must be initially * off. An interface method may be provided to turn it back on. * * Database modules that do not support transactions should implement * this method with void functionality. * */ public void commit() { if (!this.supportsTransactions) { return; } try { this.connection.commit(); } catch (SQLException e) { throw zxJDBC.newError(e); } } /** * <i>This method is optional since not all databases provide transaction * support.</i> * * In case a database does provide transactions this method causes the database * to roll back to the start of any pending transaction. Closing a connection * without committing the changes first will cause an implicit rollback to be * performed. * */ void rollback() { if (!this.supportsTransactions) { return; } try { this.connection.rollback(); } catch (SQLException e) { throw zxJDBC.newError(e); } } /** * Return a new Cursor Object using the connection. If the database does not * provide a direct cursor concept, the module will have to emulate cursors * using other means to the extent needed by this specification. * * @return a new cursor using this connection */ public PyCursor cursor() { return new PyExtendedCursor(this.connection); } /** * Return a new Cursor Object using the connection. If the database does not * provide a direct cursor concept, the module will have to emulate cursors * using other means to the extent needed by this specification. * * @param dynamicFetch if true, dynamically iterate the result * @return a new cursor using this connection */ public PyCursor cursor(boolean dynamicFetch) { return new PyExtendedCursor(this.connection, dynamicFetch); } } /** * Class ConnectionFunc * * @author * @date $today.date$ * @author last modified by $Author: bzimmer $ * @date last modified on $Date: 2001/11/20 04:55:18 $ * @version $Revision: 1.1 $ * @copyright 2001 brian zimmer */ class ConnectionFunc extends PyBuiltinFunctionSet { /** * Constructor ConnectionFunc * * @param String name * @param int index * @param int minargs * @param int maxargs * @param String doc * */ ConnectionFunc(String name, int index, int minargs, int maxargs, String doc) { super(name, index, minargs, maxargs, true, doc); } /** * Method __call__ * * @return PyObject * */ public PyObject __call__() { PyConnection c = (PyConnection)__self__; switch (index) { case 0 : c.close(); return Py.None; case 1 : c.commit(); return Py.None; case 2 : return c.cursor(); case 3 : c.rollback(); return Py.None; default : throw argCountError(0); } } /** * Method __call__ * * @param PyObject arg * * @return PyObject * */ public PyObject __call__(PyObject arg) { PyConnection c = (PyConnection)__self__; switch (index) { case 2 : return c.cursor(arg.__nonzero__()); default : throw argCountError(1); } } } --- NEW FILE: PyExtendedCursor.java --- /* * Jython Database Specification API 2.0 * * $Id: PyExtendedCursor.java,v 1.1 2001/11/20 04:55:18 bzimmer Exp $ * * Copyright (c) 2001 brian zimmer <bz...@zi...> * */ package com.ziclix.python.sql; import java.io.*; import java.sql.*; import java.util.*; import org.python.core.*; /** * A cursor with extensions to the DB API 2.0. * * @author brian zimmer * @author last revised by $Author: bzimmer $ * @version $Revision: 1.1 $ */ public class PyExtendedCursor extends PyCursor { /** Field __class__ */ public static PyClass __class__; /** * Method getPyClass * * @return PyClass * */ protected PyClass getPyClass() { return __class__; } /** Field __members__ */ protected static PyList __members__; /** Field __methods__ */ protected static PyList __methods__; static { PyObject[] m = new PyObject[7]; m[0] = new PyString("tables"); m[1] = new PyString("columns"); m[2] = new PyString("primarykeys"); m[3] = new PyString("foreignkeys"); m[4] = new PyString("procedures"); m[5] = new PyString("procedurecolumns"); m[6] = new PyString("statistics"); __methods__ = new PyList(m); m = new PyObject[0]; __members__ = new PyList(m); } /** * Constructor PyExtendedCursor * * @param Connection connection * */ PyExtendedCursor(Connection connection) { super(connection); } /** * Constructor PyExtendedCursor * * @param Connection connection * @param boolean dynamicFetch * */ PyExtendedCursor(Connection connection, boolean dynamicFetch) { super(connection, dynamicFetch); } /** * String representation of the object. * * @return a string representation of the object. */ public String toString() { return "<PyExtendedCursor object instance at " + hashCode() + ">"; } /** * Initializes the module. * * @param dict */ static public void classDictInit(PyObject dict) { PyCursor.classDictInit(dict); dict.__setitem__("__version__", Py.newString("$Revision: 1.1 $").__getslice__(Py.newInteger(11), Py.newInteger(-2), null)); dict.__setitem__("tables", new ExtendedCursorFunc("tables", 100, 4, 4, "query for table information")); dict.__setitem__("columns", new ExtendedCursorFunc("columns", 101, 4, 4, "query for column information")); dict.__setitem__("primarykeys", new ExtendedCursorFunc("primarykeys", 102, 3, 3, "query for primary keys")); dict.__setitem__("foreignkeys", new ExtendedCursorFunc("foreignkeys", 103, 6, 6, "query for foreign keys")); dict.__setitem__("procedures", new ExtendedCursorFunc("procedures", 104, 3, 3, "query for procedures")); dict.__setitem__("procedurecolumns", new ExtendedCursorFunc("procedurecolumns", 105, 4, 4, "query for procedures columns")); dict.__setitem__("statistics", new ExtendedCursorFunc("statistics", 106, 5, 5, "description of a table's indices and statistics")); dict.__setitem__("gettypeinfo", new ExtendedCursorFunc("gettypeinfo", 107, 0, 1, "query for sql type info")); dict.__setitem__("gettabletypeinfo", new ExtendedCursorFunc("gettabletypeinfo", 108, 0, 1, "query for table types")); // hide from python dict.__setitem__("classDictInit", null); dict.__setitem__("toString", null); } /** * Only table descriptions matching the catalog, schema, table name and type * criteria are returned. They are ordered by TABLE_TYPE, TABLE_SCHEM and * TABLE_NAME. * * @param qualifier * @param owner * @param table * @param type */ protected void tables(PyObject qualifier, PyObject owner, PyObject table, PyObject type) { clear(); try { String q = (qualifier == Py.None) ? null : (String)qualifier.__tojava__(String.class); String o = (owner == Py.None) ? null : (String)owner.__tojava__(String.class); String t = (table == Py.None) ? null : (String)table.__tojava__(String.class); String[] y = null; if (type != Py.None) { if (isSeq(type)) { int len = type.__len__(); y = new String[len]; for (int i = 0; i < len; i++) { y[i] = (String)type.__getitem__(i).__tojava__(String.class); } } else { y = new String[1]; y[0] = (String)type.__tojava__(String.class); } } create(this.connection.getMetaData().getTables(q, o, t, y)); } catch (SQLException e) { throw zxJDBC.newError(e); } } /** * Returns the columns for a table. * * @param qualifier * @param owner * @param table * @param column */ protected void columns(PyObject qualifier, PyObject owner, PyObject table, PyObject column) { clear(); try { String q = (qualifier == Py.None) ? null : (String)qualifier.__tojava__(String.class); String o = (owner == Py.None) ? null : (String)owner.__tojava__(String.class); String t = (table == Py.None) ? null : (String)table.__tojava__(String.class); String c = (column == Py.None) ? null : (String)column.__tojava__(String.class); create(this.connection.getMetaData().getColumns(q, o, t, c)); } catch (SQLException e) { throw zxJDBC.newError(e); } } /** * Gets a description of the stored procedures available for the qualifier and owner. * * @param qualifier * @param owner * @param procedure */ protected void procedures(PyObject qualifier, PyObject owner, PyObject procedure) { clear(); try { String q = (qualifier == Py.None) ? null : (String)qualifier.__tojava__(String.class); String o = (owner == Py.None) ? null : (String)owner.__tojava__(String.class); String p = (procedure == Py.None) ? null : (String)procedure.__tojava__(String.class); create(this.connection.getMetaData().getProcedures(q, o, p)); } catch (SQLException e) { throw zxJDBC.newError(e); } } /** * Gets the columns for the procedure. * * @param qualifier * @param owner * @param procedure * @param column */ protected void procedurecolumns(PyObject qualifier, PyObject owner, PyObject procedure, PyObject column) { clear(); try { String q = (qualifier == Py.None) ? null : (String)qualifier.__tojava__(String.class); String o = (owner == Py.None) ? null : (String)owner.__tojava__(String.class); String p = (procedure == Py.None) ? null : (String)procedure.__tojava__(String.class); String c = (column == Py.None) ? null : (String)column.__tojava__(String.class); create(this.connection.getMetaData().getProcedureColumns(q, o, p, c)); } catch (SQLException e) { throw zxJDBC.newError(e); } } /** * Gets a description of a table's primary key columns. They are ordered by * COLUMN_NAME. * * @param qualifier a schema name * @param owner an owner name * @param table a table name */ protected void primarykeys(PyObject qualifier, PyObject owner, PyObject table) { clear(); try { String q = (qualifier == Py.None) ? null : (String)qualifier.__tojava__(String.class); String o = (owner == Py.None) ? null : (String)owner.__tojava__(String.class); String t = (table == Py.None) ? null : (String)table.__tojava__(String.class); create(this.connection.getMetaData().getPrimaryKeys(q, o, t)); } catch (SQLException e) { throw zxJDBC.newError(e); } } /** * Gets a description of the foreign key columns in the foreign key table * that reference the primary key columns of the primary key table (describe * how one table imports another's key.) This should normally return a single * foreign key/primary key pair (most tables only import a foreign key from a * table once.) They are ordered by FKTABLE_CAT, FKTABLE_SCHEM, FKTABLE_NAME, * and KEY_SEQ. * * @param primaryQualifier * @param primaryOwner * @param primaryTable * @param foreignQualifier * @param foreignOwner * @param foreignTable */ protected void foreignkeys(PyObject primaryQualifier, PyObject primaryOwner, PyObject primaryTable, PyObject foreignQualifier, PyObject foreignOwner, PyObject foreignTable) { clear(); try { String pq = (primaryQualifier == Py.None) ? null : (String)primaryQualifier.__tojava__(String.class); String po = (primaryOwner == Py.None) ? null : (String)primaryOwner.__tojava__(String.class); String pt = (primaryTable == Py.None) ? null : (String)primaryTable.__tojava__(String.class); String fq = (foreignQualifier == Py.None) ? null : (String)foreignQualifier.__tojava__(String.class); String fo = (foreignOwner == Py.None) ? null : (String)foreignOwner.__tojava__(String.class); String ft = (foreignTable == Py.None) ? null : (String)foreignTable.__tojava__(String.class); create(this.connection.getMetaData().getCrossReference(pq, po, pt, fq, fo, ft)); } catch (SQLException e) { throw zxJDBC.newError(e); } } /** * Gets a description of a table's indices and statistics. They are ordered by * NON_UNIQUE, TYPE, INDEX_NAME, and ORDINAL_POSITION. * * @param qualifier * @param owner * @param table * @param unique * @param accuracy */ protected void statistics(PyObject qualifier, PyObject owner, PyObject table, PyObject unique, PyObject accuracy) { clear(); try { String q = (qualifier == Py.None) ? null : (String)qualifier.__tojava__(String.class); String o = (owner == Py.None) ? null : (String)owner.__tojava__(String.class); String t = (table == Py.None) ? null : (String)table.__tojava__(String.class); boolean u = (unique == Py.None) ? false : ((Boolean)unique.__tojava__(Boolean.class)).booleanValue(); boolean a = (accuracy == Py.None) ? false : ((Boolean)accuracy.__tojava__(Boolean.class)).booleanValue(); Set skipCols = new HashSet(); skipCols.add(new Integer(12)); create(this.connection.getMetaData().getIndexInfo(q, o, t, u, a), skipCols); } catch (SQLException e) { throw zxJDBC.newError(e); } } /** * Gets a description of the type information for a given type. * * @param type data type for which to provide information */ protected void typeinfo(PyObject type) { clear(); try { Set skipCols = new HashSet(); skipCols.add(new Integer(16)); skipCols.add(new Integer(17)); create(this.connection.getMetaData().getTypeInfo(), skipCols); // if the type is non-null, then trim the result list down to that type only // if(type != null &&!Py.None.equals(type)) { // for(int i = 0; i < ((PyObject) this.results.get(0)).__len__(); i++) { // PyObject row = ((PyObject) this.results.get(0)).__getitem__(new PyInteger(i)); // PyObject sqlType = row.__getitem__(new PyInteger(1)); // if(type.equals(sqlType)) { // this.results.remove(0); // this.results.add(0, new PyList(new PyObject[] { // row // })); // } // } // } } catch (SQLException e) { throw zxJDBC.newError(e); } } /** * Gets a description of possible table types. */ protected void tabletypeinfo() { clear(); try { create(this.connection.getMetaData().getTableTypes()); } catch (SQLException e) { throw zxJDBC.newError(e); } } } /** * Class ExtendedCursorFunc * * @author * @date $today.date$ * @author last modified by $Author: bzimmer $ * @date last modified on $Date: 2001/11/20 04:55:18 $ * @version $Revision: 1.1 $ * @copyright 2001 brian zimmer */ class ExtendedCursorFunc extends PyBuiltinFunctionSet { /** * Constructor ExtendedCursorFunc * * @param String name * @param int index * @param int argcount * @param String doc * */ ExtendedCursorFunc(String name, int index, int argcount, String doc) { super(name, index, argcount, argcount, true, doc); } /** * Constructor ExtendedCursorFunc * * @param String name * @param int index * @param int minargs * @param int maxargs * @param String doc * */ ExtendedCursorFunc(String name, int index, int minargs, int maxargs, String doc) { super(name, index, minargs, maxargs, true, doc); } /** * Method __call__ * * @return PyObject * */ public PyObject __call__() { PyExtendedCursor cursor = (PyExtendedCursor)__self__; switch (index) { case 107 : cursor.typeinfo(Py.None); return Py.None; case 108 : cursor.tabletypeinfo(); return Py.None; default : throw argCountError(0); } } /** * Method __call__ * * @param PyObject arga * * @return PyObject * */ public PyObject __call__(PyObject arga) { PyExtendedCursor cursor = (PyExtendedCursor)__self__; switch (index) { case 107 : cursor.typeinfo(arga); return Py.None; default : throw argCountError(1); } } /** * Method __call__ * * @param PyObject arga * @param PyObject argb * @param PyObject argc * * @return PyObject * */ public PyObject __call__(PyObject arga, PyObject argb, PyObject argc) { PyExtendedCursor cursor = (PyExtendedCursor)__self__; switch (index) { case 102 : cursor.primarykeys(arga, argb, argc); return Py.None; case 104 : cursor.procedures(arga, argb, argc); return Py.None; default : throw argCountError(3); } } /** * Method fancyCall * * @param PyObject[] args * * @return PyObject * */ public PyObject fancyCall(PyObject[] args) { PyExtendedCursor cursor = (PyExtendedCursor)__self__; switch (index) { case 103 : cursor.foreignkeys(args[0], args[1], args[2], args[3], args[4], args[5]); return Py.None; case 106 : cursor.statistics(args[0], args[1], args[2], args[3], args[4]); return Py.None; default : throw argCountError(args.length); } } /** * Method __call__ * * @param PyObject arg1 * @param PyObject arg2 * @param PyObject arg3 * @param PyObject arg4 * * @return PyObject * */ public PyObject __call__(PyObject arg1, PyObject arg2, PyObject arg3, PyObject arg4) { PyExtendedCursor cursor = (PyExtendedCursor)__self__; switch (index) { case 100 : cursor.tables(arg1, arg2, arg3, arg4); return Py.None; case 101 : cursor.columns(arg1, arg2, arg3, arg4); return Py.None; case 105 : cursor.procedurecolumns(arg1, arg2, arg3, arg4); return Py.None; default : throw argCountError(4); } } } --- NEW FILE: zxJDBC.java --- /* * Jython Database Specification API 2.0 * * $Id: zxJDBC.java,v 1.1 2001/11/20 04:55:18 bzimmer Exp $ * * Copyright (c) 2001 brian zimmer <bz...@zi...> * */ package com.ziclix.python.sql; import java.io.*; import java.sql.*; import java.util.*; import java.text.*; import java.lang.reflect.*; import org.python.core.*; /** * Creates database connections. * * <pre> * from com.ziclix.python.sql import zxJDBC * db = zxJDBC.connect("jdbc:mysql://localhost:3306/MySql", None, None, "org.gjt.mm.mysql.Driver") * </pre> * * @author brian zimmer * @author last revised by $Author: bzimmer $ * @version $Revision: 1.1 $ */ public class zxJDBC extends PyObject implements ClassDictInit { /** Field Error */ public static PyObject Error = Py.None; /** Field Warning */ public static PyObject Warning = Py.None; /** Field InterfaceError */ public static PyObject InterfaceError = Py.None; /** Field DatabaseError */ public static PyObject DatabaseError = Py.None; /** Field InternalError */ public static PyObject InternalError = Py.None; /** Field OperationalError */ public static PyObject OperationalError = Py.None; /** Field ProgrammingError */ public static PyObject ProgrammingError = Py.None; /** Field IntegrityError */ public static PyObject IntegrityError = Py.None; /** Field DataError */ public static PyObject DataError = Py.None; /** Field NotSupportedError */ public static PyObject NotSupportedError = Py.None; /** The ResourceBundle with error messages and doc strings */ private static ResourceBundle resourceBundle = null; static { try { resourceBundle = ResourceBundle.getBundle("com.ziclix.python.sql.resource.zxJDBCMessages"); } catch (MissingResourceException e) { throw new RuntimeException("missing zxjdbc resource bundle"); } } /** * Initializes the module. * * @param dict */ public static void classDictInit(PyObject dict) { dict.__setitem__("apilevel", new PyString("2.0")); dict.__setitem__("threadsafety", new PyInteger(1)); dict.__setitem__("paramstyle", new PyString("qmark")); dict.__setitem__("__version__", Py.newString("$Revision: 1.1 $").__getslice__(Py.newInteger(11), Py.newInteger(-2), null)); dict.__setitem__("Date", new zxJDBCFunc("Date", 1, 3, 3, false, "construct a Date from year, month, day")); dict.__setitem__("Time", new zxJDBCFunc("Time", 2, 3, 3, false, "construct a Date from hour, minute, second")); dict.__setitem__("Timestamp", new zxJDBCFunc("Timestamp", 3, 6, 6, false, "construct a Timestamp from year, month, day, hour, minute, second")); dict.__setitem__("DateFromTicks", new zxJDBCFunc("DateFromTicks", 4, 1, 1, false, "construct a Date from seconds since the epoch")); dict.__setitem__("TimeFromTicks", new zxJDBCFunc("TimeFromTicks", 5, 1, 1, false, "construct a Time from seconds since the epoch")); dict.__setitem__("TimestampFromTicks", new zxJDBCFunc("TimestampFromTicks", 6, 1, 1, false, "construct a Timestamp from seconds since the epoch")); zxJDBC._addSqlTypes(dict); zxJDBC._addConnectors(dict); zxJDBC._buildExceptions(dict); // hide from python dict.__setitem__("initModule", null); dict.__setitem__("toString", null); dict.__setitem__("getPyClass", null); dict.__setitem__("classDictInit", null); dict.__setitem__("_addSqlTypes", null); dict.__setitem__("_addConnectors", null); dict.__setitem__("_buildExceptions", null); dict.__setitem__("_empty__init__", null); dict.__setitem__("buildClass", null); dict.__setitem__("createExceptionMessage", null); dict.__setitem__("newError", null); dict.__setitem__("resourceBundle", null); dict.__setitem__("getString", null); } /** Field __class__ */ public static PyClass __class__; /** * Method getPyClass * * @return PyClass * */ protected PyClass getPyClass() { return __class__; } /** * Add the types from java.sql.Types * * @param PyObject dict * * @throws PyException * */ protected static void _addSqlTypes(PyObject dict) throws PyException { PyDictionary sqltype = new PyDictionary(); dict.__setitem__("sqltype", sqltype); try { Class c = Class.forName("java.sql.Types"); Field[] fields = c.getFields(); for (int i = 0; i < fields.length; i++) { Field f = fields[i]; dict.__setitem__(Py.newString(f.getName()), new PyInteger(f.getInt(c))); sqltype.__setitem__(new PyInteger(f.getInt(c)), Py.newString(f.getName())); } } catch (Exception e) { throw newError(e); } return; } /** * Add all the possible connectors * * @param PyObject dict * * @throws PyException * */ protected static void _addConnectors(PyObject dict) throws PyException { PyObject connector = Py.None; Properties props = new Properties(); props.put("connect", "com.ziclix.python.sql.connect.Connect"); props.put("lookup", "com.ziclix.python.sql.connect.Lookup"); props.put("connectx", "com.ziclix.python.sql.connect.Connectx"); java.util.Enumeration names = props.propertyNames(); while (names.hasMoreElements()) { String name = ((String)names.nextElement()).trim(); String className = ((String)props.getProperty(name)).trim(); try { connector = (PyObject)Class.forName(className).newInstance(); dict.__setitem__(name, connector); Py.writeComment("zxJDBC", "loaded connector [" + className + "] as [" + name + "]"); } catch (Throwable t) { Py.writeComment("zxJDBC", "failed to load connector [" + name + "] using class [" + className + "]"); } } return; } /** * Create the exception classes and get their descriptions from the resource bundle. */ protected static void _buildExceptions(PyObject dict) { Error = buildClass("Error", Py.StandardError, "_empty__init__"); Warning = buildClass("Warning", Py.StandardError, "_empty__init__"); InterfaceError = buildClass("InterfaceError", Error, "_empty__init__"); DatabaseError = buildClass("DatabaseError", Error, "_empty__init__"); InternalError = buildClass("InternalError", DatabaseError, "_empty__init__"); OperationalError = buildClass("OperationalError", DatabaseError, "_empty__init__"); ProgrammingError = buildClass("ProgrammingError", DatabaseError, "_empty__init__"); IntegrityError = buildClass("IntegrityError", DatabaseError, "_empty__init__"); DataError = buildClass("DataError", DatabaseError, "_empty__init__"); NotSupportedError = buildClass("NotSupportedError", DatabaseError, "_empty__init__"); } /** * Method _empty__init__ * * @param PyObject[] arg * @param String[] kws * * @return PyObject * */ public static PyObject _empty__init__(PyObject[] arg, String[] kws) { PyObject dict = new PyStringMap(); dict.__setitem__("__module__", new PyString("zxJDBC")); return dict; } /** * Return the string associated with the key for the default resource bundle. It * first checks for 'key.N' where N starts at 0 and increments by one. If any indexed * key is found, the results of all the indexed values are concatenated with the line * separator. If no indexed key is found, it defaults to checking the bundle by the * key value alone. */ public static String getString(String key) { int i = 0; List lines = null; String resource = null; while (true) { try { resource = resourceBundle.getString(key + "." + (i++)); if (lines == null) { lines = new ArrayList(); } lines.add(resource); } catch (MissingResourceException e) { break; } } if ((lines == null) || (lines.size() == 0)) { resource = resourceBundle.getString(key); } else { String sep = System.getProperty("line.separator"); StringBuffer sb = new StringBuffer(); for (i = 0; i < lines.size() - 1; i++) { sb.append(lines.get(i)).append(sep); } sb.append(lines.get(lines.size() - 1)); resource = sb.toString(); } return resource; } /** * Return a formatted string. The key is used to get the format and the values * are passed, along with the format, to a MessageFormat who formats it appropriately. */ public static String getString(String key, Object[] values) { String format = getString(key); return MessageFormat.format(format, values); } /** * Return a newly instantiated PyException. */ public static PyException makeException(PyObject type, String msg) { return Py.makeException(type, Py.newString((msg == null) ? "" : msg)); } /** * Return a newly instantiated Error. */ public static PyException newError(String msg) { return zxJDBC.makeException(Error, msg); } /** * Return a newly instantiated Error. */ public static PyException newError(Throwable e) { try { return (PyException)e; } catch (ClassCastException ex) {} try { StringBuffer buffer = new StringBuffer(); createExceptionMessage((SQLException)e, buffer, 0); return newError(buffer.toString()); } catch (ClassCastException ex) {} return newError(e.getMessage()); } /** * Create SQL exception messages * * @param SQLException exception * @param StringBuffer buffer * @param int level * */ protected static void createExceptionMessage(SQLException exception, StringBuffer buffer, int level) { buffer.append(exception.getMessage()); buffer.append(" [SQLCode: " + exception.getErrorCode() + "]"); if (exception.getSQLState() != null) { buffer.append(", [SQLState: " + exception.getSQLState() + "]"); } if (exception.getNextException() != null) { buffer.append(System.getProperty("line.separator")); createExceptionMessage(exception.getNextException(), buffer, level + 1); } } /** * This function constructs an object holding a date value. */ protected static PyObject Date(int year, int month, int day) { Calendar c = Calendar.getInstance(); c.set(Calendar.YEAR, year); c.set(Calendar.MONTH, month - 1); c.set(Calendar.DATE, day); return DateFromTicks(c.getTime().getTime() / 1000); } /** * This function constructs an object holding a time value. */ protected static PyObject Time(int hour, int minute, int second) { Calendar c = Calendar.getInstance(); c.set(Calendar.HOUR, hour); c.set(Calendar.MINUTE, minute); c.set(Calendar.SECOND, second); return TimeFromTicks(c.getTime().getTime() / 1000); } /** * This function constructs an object holding a time stamp value. */ protected static PyObject Timestamp(int year, int month, int day, int hour, int minute, int second) { Calendar c = Calendar.getInstance(); c.set(Calendar.YEAR, year); c.set(Calendar.MONTH, month - 1); c.set(Calendar.DATE, day); c.set(Calendar.HOUR, hour); c.set(Calendar.MINUTE, minute); c.set(Calendar.SECOND, second); c.set(Calendar.MILLISECOND, 0); return TimestampFromTicks(c.getTime().getTime() / 1000); } /** * This function constructs an object holding a date value from the * given ticks value (number of seconds since the epoch; see the * documentation of the standard Python <i>time</i> module for details). * * <i>Note:</i> The DB API 2.0 spec calls for time in seconds since the epoch * while the Java Date object returns time in milliseconds since the epoch. * This module adheres to the python API and will therefore use time in * seconds rather than milliseconds, so adjust any Java code accordingly. * * @param ticks number of seconds since the epoch */ protected static PyObject DateFromTicks(long ticks) { Calendar c = Calendar.getInstance(); c.setTime(new java.util.Date(ticks * 1000)); c.set(Calendar.HOUR, 0); c.set(Calendar.MINUTE, 0); c.set(Calendar.SECOND, 0); c.set(Calendar.MILLISECOND, 0); return Py.java2py(new java.sql.Date(c.getTime().getTime())); } /** * This function constructs an object holding a time value from the * given ticks value (number of seconds since the epoch; see the * documentation of the standard Python <i>time</i> module for details). * * <i>Note:</i> The DB API 2.0 spec calls for time in seconds since the epoch * while the Java Date object returns time in milliseconds since the epoch. * This module adheres to the python API and will therefore use time in * seconds rather than milliseconds, so adjust any Java code accordingly. * * @param ticks number of seconds since the epoch */ protected static PyObject TimeFromTicks(long ticks) { return Py.java2py(new Time(ticks * 1000)); } /** * This function constructs an object holding a time stamp value from * the given ticks value (number of... [truncated message content] |