diff --git a/README.rst b/README.rst index 70fcb94..15d3cf1 100644 --- a/README.rst +++ b/README.rst @@ -72,22 +72,25 @@ the ``connect`` method. This gives you a DB-API_ conform connection to the database. The first argument to ``connect`` is the name of the Java driver -class. Then you can supply a single argument or a sequence of -arguments that are internally passed to the Java -``DriverManager.getConnection`` method. Usually this is the JDBC -connection URL. See the Javadoc of ``DriverManager`` class for -details. +class. The second argument is a string with the JDBC connection +URL. Third you can optionally supply a sequence consisting of user and +password or alternatively a dictionary containing arguments that are +internally passed as properties to the Java +``DriverManager.getConnection`` method. See the Javadoc of +``DriverManager`` class for details. -The next parameter to ``connect`` is optional and specifies the -jar-Files of the driver if your classpath isn't set up sufficiently -yet. The classpath set in ``CLASSPATH`` environment variable will be -honored. See the documentation of your Java runtime environment. +The next parameter to ``connect`` is optional as well and specifies +the jar-Files of the driver if your classpath isn't set up +sufficiently yet. The classpath set in ``CLASSPATH`` environment +variable will be honored. See the documentation of your Java runtime +environment. Here is an example: >>> import jaydebeapi >>> conn = jaydebeapi.connect('org.hsqldb.jdbcDriver', -... ['jdbc:hsqldb:mem:.', 'SA', ''], +... 'jdbc:hsqldb:mem:.', +... ['SA', ''], ... '/path/to/hsqldb.jar',) >>> curs = conn.cursor() >>> curs.execute('create table CUSTOMER' @@ -144,6 +147,11 @@ Changelog ========= - Next version - unreleased + + - Allow for db properties to be passed to the connect + method. *Probably incompatible to code based on previous + versions.* See documentation of the connect method. + - 0.2.0 - 2015-04-26 - Python 3 support (requires JPype1 >= 0.6.0). diff --git a/jaydebeapi/__init__.py b/jaydebeapi/__init__.py index 51c2b84..4d51258 100644 --- a/jaydebeapi/__init__.py +++ b/jaydebeapi/__init__.py @@ -83,7 +83,7 @@ def _handle_sql_exception_jython(): exc_type = InterfaceError reraise(exc_type, exc_info[1], exc_info[2]) -def _jdbc_connect_jython(jclassname, jars, libs, *args): +def _jdbc_connect_jython(jclassname, url, driver_args, jars, libs): if _jdbc_name_to_const is None: from java.sql import Types types = Types @@ -114,7 +114,15 @@ def _jdbc_connect_jython(jclassname, jars, libs, *args): _jython_set_classpath(jars) Class.forName(jclassname).newInstance() from java.sql import DriverManager - return DriverManager.getConnection(*args) + if isinstance(driver_args, dict): + from java.util import Properties + info = Properties() + for k, v in driver_args.iteritems(): + info.setProperty(k, v) + dargs = [ info ] + else: + dargs = driver_args + return DriverManager.getConnection(url, *dargs) def _jython_set_classpath(jars): ''' @@ -147,7 +155,7 @@ def _handle_sql_exception_jpype(): exc_type = InterfaceError reraise(exc_type, exc_info[1], exc_info[2]) -def _jdbc_connect_jpype(jclassname, jars, libs, *driver_args): +def _jdbc_connect_jpype(jclassname, url, driver_args, jars, libs): import jpype if not jpype.isJVMStarted(): args = [] @@ -180,7 +188,15 @@ def _jdbc_connect_jpype(jclassname, jars, libs, *driver_args): return jpype.JArray(jpype.JByte, 1)(data) # register driver for DriverManager jpype.JClass(jclassname) - return jpype.java.sql.DriverManager.getConnection(*driver_args) + if isinstance(driver_args, dict): + Properties = jpype.java.util.Properties + info = Properties() + for k, v in driver_args.iteritems(): + info.setProperty(k, v) + dargs = [ info ] + else: + dargs = driver_args + return jpype.java.sql.DriverManager.getConnection(url, *dargs) def _get_classpath(): """Extract CLASSPATH from system environment as JPype doesn't seem @@ -330,15 +346,18 @@ def TimestampFromTicks(ticks): return apply(Timestamp, time.localtime(ticks)[:6]) # DB-API 2.0 Module Interface connect constructor -def connect(jclassname, driver_args, jars=None, libs=None): +def connect(jclassname, url, driver_args=None, jars=None, libs=None): """Open a connection to a database using a JDBC driver and return a Connection instance. jclassname: Full qualified Java class name of the JDBC driver. - driver_args: Argument or sequence of arguments to be passed to the - Java DriverManager.getConnection method. Usually the - database URL. See - http://docs.oracle.com/javase/6/docs/api/java/sql/DriverManager.html + url: Database url as required by the JDBC driver. + driver_args: Dictionary or sequence of arguments to be passed to + the Java DriverManager.getConnection method. Usually + sequence of username and password for the db. Alternatively + a dictionary of connection arguments (where `user` and + `password` would probably be included). See + http://docs.oracle.com/javase/7/docs/api/java/sql/DriverManager.html for more details jars: Jar filename or sequence of filenames for the JDBC driver libs: Dll/so filenames or sequence of dlls/sos used as shared @@ -346,6 +365,8 @@ def connect(jclassname, driver_args, jars=None, libs=None): """ if isinstance(driver_args, string_type): driver_args = [ driver_args ] + if not driver_args: + driver_args = [] if jars: if isinstance(jars, string_type): jars = [ jars ] @@ -356,7 +377,7 @@ def connect(jclassname, driver_args, jars=None, libs=None): libs = [ libs ] else: libs = [] - jconn = _jdbc_connect(jclassname, jars, libs, *driver_args) + jconn = _jdbc_connect(jclassname, url, driver_args, jars, libs) return Connection(jconn, _converters) # DB-API 2.0 Connection Object diff --git a/test/test_integration.py b/test/test_integration.py index 42b6117..8818975 100644 --- a/test/test_integration.py +++ b/test/test_integration.py @@ -244,7 +244,7 @@ class SqliteXerialTest(SqliteTestBase, unittest.TestCase): def connect(self): #http://bitbucket.org/xerial/sqlite-jdbc # sqlite-jdbc-3.7.2.jar - driver, driver_args = 'org.sqlite.JDBC', 'jdbc:sqlite::memory:' + driver, url = 'org.sqlite.JDBC', 'jdbc:sqlite::memory:' # db2jcc # driver, driver_args = 'com.ibm.db2.jcc.DB2Driver', \ # ['jdbc:db2://4.100.73.81:50000/db2t', 'user', 'passwd'] @@ -256,7 +256,7 @@ class SqliteXerialTest(SqliteTestBase, unittest.TestCase): # driver, driver_args = 'oracle.jdbc.OracleDriver', \ # ['jdbc:oracle:thin:@//hh-cluster-scan:1521/HH_TPP', # 'user', 'passwd'] - return jaydebeapi, jaydebeapi.connect(driver, driver_args) + return jaydebeapi, jaydebeapi.connect(driver, url) @unittest.skipUnless(is_jython(), "don't know how to support blob") def test_execute_type_blob(self): @@ -267,10 +267,25 @@ class HsqldbTest(IntegrationTestBase, unittest.TestCase): def connect(self): # http://hsqldb.org/ # hsqldb.jar - driver, driver_args = 'org.hsqldb.jdbcDriver', ['jdbc:hsqldb:mem:.', - 'SA', ''] - return jaydebeapi, jaydebeapi.connect(driver, driver_args) + driver, url, driver_args = ( 'org.hsqldb.jdbcDriver', + 'jdbc:hsqldb:mem:.', + ['SA', ''] ) + return jaydebeapi, jaydebeapi.connect(driver, url, driver_args) def setUpSql(self): self.sql_file(os.path.join(_THIS_DIR, 'data', 'create_hsqldb.sql')) self.sql_file(os.path.join(_THIS_DIR, 'data', 'insert.sql')) + +class PropertiesDriverArgsPassingTest(unittest.TestCase): + + def test_connect_with_sequence(self): + driver, url, driver_args = ( 'org.hsqldb.jdbcDriver', + 'jdbc:hsqldb:mem:.', + ['SA', ''] ) + jaydebeapi.connect(driver, url, driver_args) + + def test_connect_with_properties(self): + driver, url, driver_args = ( 'org.hsqldb.jdbcDriver', + 'jdbc:hsqldb:mem:.', + {'user': 'SA', 'password': '' } ) + jaydebeapi.connect(driver, url, driver_args)