src.com.ziclix.python.sql.PyConnection Maven / Gradle / Ivy
Show all versions of jython-standalone Show documentation
/*
* Jython Database Specification API 2.0
*
*
* Copyright (c) 2001 brian zimmer
*
*/
package com.ziclix.python.sql;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Collections;
import java.util.WeakHashMap;
import java.util.Set;
import org.python.core.ClassDictInit;
import org.python.core.ContextManager;
import org.python.core.Py;
import org.python.core.PyBuiltinMethodSet;
import org.python.core.PyException;
import org.python.core.PyInteger;
import org.python.core.PyList;
import org.python.core.PyObject;
import org.python.core.PyString;
import org.python.core.PyUnicode;
import org.python.core.ThreadState;
import org.python.core.Traverseproc;
import org.python.core.Visitproc;
import com.ziclix.python.sql.util.PyArgParser;
/**
* A connection to the database.
*
* @author brian zimmer
*/
public class PyConnection extends PyObject implements ClassDictInit, ContextManager, Traverseproc {
/** True if closed. */
protected boolean closed;
/** Whether transactions are supported. */
protected boolean supportsTransactions;
/** Whether multiple ResultSets are supported. */
protected boolean supportsMultipleResultSets;
/** The underlying java.sql.Connection. */
protected Connection connection;
/** Underlying cursors. */
private Set cursors;
/** Underlying statements. */
private Set statements;
/** Field __members__ */
protected static PyList __members__;
/** Field __methods__ */
protected static PyList __methods__;
static {
PyObject[] m = new PyObject[5];
m[0] = new PyString("close");
m[1] = new PyString("commit");
m[2] = new PyString("cursor");
m[3] = new PyString("rollback");
m[4] = new PyString("nativesql");
__methods__ = new PyList(m);
m = new PyObject[10];
m[0] = new PyString("autocommit");
m[1] = new PyString("dbname");
m[2] = new PyString("dbversion");
m[3] = new PyString("drivername");
m[4] = new PyString("driverversion");
m[5] = new PyString("url");
m[6] = new PyString("__connection__");
m[7] = new PyString("__cursors__");
m[8] = new PyString("__statements__");
m[9] = new PyString("closed");
__members__ = new PyList(m);
}
/**
* Create a PyConnection with the open connection.
*
* @param connection
* @throws SQLException
*/
public PyConnection(Connection connection) throws SQLException {
this.closed = false;
cursors = Collections.newSetFromMap(new WeakHashMap());
cursors = Collections.synchronizedSet(cursors);
this.connection = connection;
statements = Collections.newSetFromMap(new WeakHashMap());
statements = Collections.synchronizedSet(statements);
this.supportsTransactions = this.connection.getMetaData().supportsTransactions();
this.supportsMultipleResultSets =
this.connection.getMetaData().supportsMultipleResultSets();
if (this.supportsTransactions) {
this.connection.setAutoCommit(false);
}
}
/**
* Produces a string representation of the object.
*
* @return string representation of the object.
*/
@Override
public String toString() {
try {
return String.format("", Py.idstr(this),
connection.getMetaData().getUserName(),
connection.getMetaData().getURL());
} catch (SQLException e) {
return String.format("
* Database modules that do not support transactions should implement this method with
* void functionality.
*/
public void commit() {
if (closed) {
throw zxJDBC.makeException(zxJDBC.ProgrammingError, "connection is closed");
}
if (!this.supportsTransactions) {
return;
}
try {
this.connection.commit();
} catch (SQLException e) {
throw zxJDBC.makeException(e);
}
}
/**
* This method is optional since not all databases provide transaction support.
*
* 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.
*/
public void rollback() {
if (closed) {
throw zxJDBC.makeException(zxJDBC.ProgrammingError, "connection is closed");
}
if (!this.supportsTransactions) {
return;
}
try {
this.connection.rollback();
} catch (SQLException e) {
throw zxJDBC.makeException(e);
}
}
/**
* Converts the given SQL statement into the system's native SQL grammar. A driver may
* convert the JDBC sql grammar into its system's native SQL grammar prior to sending
* it; this method returns the native form of the statement that the driver would have
* sent.
*
* @param nativeSQL
* @return the native form of this statement
*/
public PyObject nativesql(PyObject nativeSQL) {
if (closed) {
throw zxJDBC.makeException(zxJDBC.ProgrammingError, "connection is closed");
}
if (nativeSQL == Py.None) {
return Py.None;
}
try {
if (nativeSQL instanceof PyUnicode) {
return Py.newUnicode(this.connection.nativeSQL(nativeSQL.toString()));
}
return Py.newString(this.connection.nativeSQL(nativeSQL.__str__().toString()));
} catch (SQLException e) {
throw zxJDBC.makeException(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 cursor(false);
}
/**
* 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 this.cursor(dynamicFetch, Py.None, Py.None);
}
/**
* 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
* @param rsType the type of the underlying ResultSet
* @param rsConcur the concurrency of the underlying ResultSet
* @return a new cursor using this connection
*/
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);
this.cursors.add(cursor);
return cursor;
}
/**
* Remove an open PyCursor.
*
* @param cursor
*/
void remove(PyCursor cursor) {
if (closed) {
return;
}
this.cursors.remove(cursor);
}
/**
* Method register
*
* @param statement statement
*/
void add(PyStatement statement) {
if (closed) {
return;
}
this.statements.add(statement);
}
/**
* Method contains
*
* @param statement statement
* @return boolean
*/
boolean contains(PyStatement statement) {
if (closed) {
return false;
}
return this.statements.contains(statement);
}
public PyObject __enter__(ThreadState ts) {
return this;
}
public PyObject __enter__() {
return this;
}
public boolean __exit__(ThreadState ts, PyException exception) {
if (exception == null) {
commit();
} else {
rollback();
}
return false;
}
public boolean __exit__(PyObject type, PyObject value, PyObject traceback) {
if (type == null || type == Py.None) {
commit();
} else {
rollback();
}
return false;
}
/* Traverseproc implementation */
@Override
public int traverse(Visitproc visit, Object arg) {
int retVal;
for (PyObject ob: cursors) {
if (ob != null) {
retVal = visit.visit(ob, arg);
if (retVal != 0) {
return retVal;
}
}
}
for (PyObject ob: statements) {
if (ob != null) {
retVal = visit.visit(ob, arg);
if (retVal != 0) {
return retVal;
}
}
}
return 0;
}
@Override
public boolean refersDirectlyTo(PyObject ob) {
if (ob == null) {
return false;
}
if (cursors != null && cursors.contains(ob)) {
return true;
} else if (statements != null && statements.contains(ob)) {
return true;
} else {
return false;
}
}
}
class ConnectionFunc extends PyBuiltinMethodSet {
ConnectionFunc(String name, int index, int minargs, int maxargs, String doc) {
super(name, index, minargs, maxargs, doc, PyConnection.class);
}
@Override
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;
case 5:
return c.__enter__();
default:
throw info.unexpectedCall(0, false);
}
}
@Override
public PyObject __call__(PyObject arg) {
PyConnection c = (PyConnection) __self__;
switch (index) {
case 2:
return c.cursor(arg.__nonzero__());
case 4:
return c.nativesql(arg);
default:
throw info.unexpectedCall(1, false);
}
}
@Override
public PyObject __call__(PyObject arg1, PyObject arg2, PyObject arg3) {
PyConnection c = (PyConnection) __self__;
switch (index) {
case 2:
return c.cursor(arg1.__nonzero__(), arg2, arg3);
case 6:
return Py.newBoolean(c.__exit__(arg1, arg2, arg3));
default:
throw info.unexpectedCall(3, false);
}
}
@Override
public PyObject __call__(PyObject[] args, String[] keywords) {
PyConnection c = (PyConnection) __self__;
PyArgParser parser = new PyArgParser(args, keywords);
switch (index) {
case 2:
PyObject dynamic = parser.kw("dynamic", Py.None);
PyObject rstype = parser.kw("rstype", Py.None);
PyObject rsconcur = parser.kw("rsconcur", Py.None);
dynamic = (parser.numArg() >= 1) ? parser.arg(0) : dynamic;
rstype = (parser.numArg() >= 2) ? parser.arg(1) : rstype;
rsconcur = (parser.numArg() >= 3) ? parser.arg(2) : rsconcur;
return c.cursor(dynamic.__nonzero__(), rstype, rsconcur);
default:
throw info.unexpectedCall(args.length, true);
}
}
}