From 62a1e558d141a575e2dcf62d913ea17046a552a0 Mon Sep 17 00:00:00 2001 From: Kevin Martin Date: Mon, 19 Dec 2016 14:45:10 -0500 Subject: [PATCH 1/9] Add support for non-prepared statements and driver properties. --- jaydebeapi/__init__.py | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/jaydebeapi/__init__.py b/jaydebeapi/__init__.py index 51c2b84..dbdc0d5 100644 --- a/jaydebeapi/__init__.py +++ b/jaydebeapi/__init__.py @@ -7,12 +7,12 @@ # it under the terms of the GNU Lesser General Public License as # published by the Free Software Foundation, either version 3 of the # License, or (at your option) any later version. -# +# # JayDeBeApi is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. -# +# # You should have received a copy of the GNU Lesser General Public # License along with JayDeBeApi. If not, see # . @@ -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, jars, libs, props, *args): if _jdbc_name_to_const is None: from java.sql import Types types = Types @@ -146,8 +146,8 @@ def _handle_sql_exception_jpype(): else: 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, jars, libs, props, *driver_args): import jpype if not jpype.isJVMStarted(): args = [] @@ -180,6 +180,13 @@ def _java_array_byte(data): return jpype.JArray(jpype.JByte, 1)(data) # register driver for DriverManager jpype.JClass(jclassname) + + if props is not None: + jprops = jpype.java.util.Properties() + for k, v in props.iteritems(): + jprops.put(k, v) + return jpype.java.sql.DriverManager.getConnection(driver_args[0], jprops) + return jpype.java.sql.DriverManager.getConnection(*driver_args) def _get_classpath(): @@ -330,7 +337,7 @@ 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, driver_args, jars=None, libs=None, props=None): """Open a connection to a database using a JDBC driver and return a Connection instance. @@ -356,7 +363,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, jars, libs, props, *driver_args) return Connection(jconn, _converters) # DB-API 2.0 Connection Object @@ -390,6 +397,10 @@ def commit(self): except: _handle_sql_exception() + def execute(self, sql): + stmt = self.jconn.createStatement() + return stmt.executeQuery(sql) + def rollback(self): try: self.jconn.rollback() From 2cd93ef8bacf7d7cc2fc798547ef8b08bd39d820 Mon Sep 17 00:00:00 2001 From: tdawber Date: Thu, 22 Dec 2016 14:31:03 +1100 Subject: [PATCH 2/9] Move unprepared statements into cursor --- jaydebeapi/__init__.py | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/jaydebeapi/__init__.py b/jaydebeapi/__init__.py index dbdc0d5..8c244fe 100644 --- a/jaydebeapi/__init__.py +++ b/jaydebeapi/__init__.py @@ -397,10 +397,6 @@ def commit(self): except: _handle_sql_exception() - def execute(self, sql): - stmt = self.jconn.createStatement() - return stmt.executeQuery(sql) - def rollback(self): try: self.jconn.rollback() @@ -481,15 +477,25 @@ def _set_stmt_parms(self, prep_stmt, parameters): def execute(self, operation, parameters=None): if self._connection._closed: raise Error() - if not parameters: - parameters = () + self._close_last() - self._prep = self._connection.jconn.prepareStatement(operation) - self._set_stmt_parms(self._prep, parameters) - try: - is_rs = self._prep.execute() - except: - _handle_sql_exception() + + if parameters == None: + self._prep = self._connection.jconn.createStatement() + + try: + is_rs = self._prep.execute(operation) + except: + _handle_sql_exception() + else: + self._prep = self._connection.jconn.prepareStatement(operation) + self._set_stmt_parms(self._prep, parameters) + + try: + is_rs = self._prep.execute() + except: + _handle_sql_exception() + if is_rs: self._rs = self._prep.getResultSet() self._meta = self._rs.getMetaData() From 413180629c2a11525ac54a304acdf1b0a3c0e6f9 Mon Sep 17 00:00:00 2001 From: tdawber Date: Wed, 28 Dec 2016 11:46:33 +1100 Subject: [PATCH 3/9] add statements to mock driver --- .../java/org/jaydebeapi/mockdriver/MockConnection.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/mockdriver/src/main/java/org/jaydebeapi/mockdriver/MockConnection.java b/mockdriver/src/main/java/org/jaydebeapi/mockdriver/MockConnection.java index 8ed0703..ae11d01 100644 --- a/mockdriver/src/main/java/org/jaydebeapi/mockdriver/MockConnection.java +++ b/mockdriver/src/main/java/org/jaydebeapi/mockdriver/MockConnection.java @@ -2,6 +2,7 @@ import java.lang.reflect.Field; import java.sql.Connection; +import java.sql.Statement; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.ResultSetMetaData; @@ -25,16 +26,22 @@ public final void mockExceptionOnRollback(String className, String exceptionMess public final void mockExceptionOnExecute(String className, String exceptionMessage) throws SQLException { PreparedStatement mockPreparedStatement = Mockito.mock(PreparedStatement.class); + Statement mockStatement = Mockito.mock(Statement.class); Throwable exception = createException(className, exceptionMessage); Mockito.when(mockPreparedStatement.execute()).thenThrow(exception); + Mockito.when(mockStatement.execute(Mockito.anyString())).thenThrow(exception); Mockito.when(this.prepareStatement(Mockito.anyString())).thenReturn(mockPreparedStatement); + Mockito.when(this.createStatement()).thenReturn(mockStatement); } public final void mockType(String sqlTypesName) throws SQLException { PreparedStatement mockPreparedStatement = Mockito.mock(PreparedStatement.class); + Statement mockStatement = Mockito.mock(Statement.class); Mockito.when(mockPreparedStatement.execute()).thenReturn(true); + Mockito.when(mockStatement.execute(Mockito.anyString())).thenReturn(true); mockResultSet = Mockito.mock(ResultSet.class, "ResultSet(for type " + sqlTypesName + ")"); Mockito.when(mockPreparedStatement.getResultSet()).thenReturn(mockResultSet); + Mockito.when(mockStatement.getResultSet()).thenReturn(mockResultSet); Mockito.when(mockResultSet.next()).thenReturn(true); ResultSetMetaData mockMetaData = Mockito.mock(ResultSetMetaData.class); Mockito.when(mockResultSet.getMetaData()).thenReturn(mockMetaData); @@ -42,6 +49,7 @@ public final void mockType(String sqlTypesName) throws SQLException { int sqlTypeCode = extractTypeCodeForName(sqlTypesName); Mockito.when(mockMetaData.getColumnType(1)).thenReturn(sqlTypeCode); Mockito.when(this.prepareStatement(Mockito.anyString())).thenReturn(mockPreparedStatement); + Mockito.when(this.createStatement()).thenReturn(mockStatement); } public final ResultSet verifyResultSet() { From 3542a80178feeb85f92616c82ca022cbdd620c55 Mon Sep 17 00:00:00 2001 From: tdawber Date: Wed, 28 Dec 2016 12:33:26 +1100 Subject: [PATCH 4/9] add error tests --- test/test_integration.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/test_integration.py b/test/test_integration.py index 42b6117..75d50c6 100644 --- a/test/test_integration.py +++ b/test/test_integration.py @@ -207,6 +207,20 @@ def test_execute_different_rowcounts(self): cursor.execute("select * from ACCOUNT") self.assertEqual(cursor.rowcount, -1) + def test_sql_exception_on_execute(self): + cursor = self.conn.cursor() + try: + cursor.execute("dummy stmt") + except jaydebeapi.DatabaseError as e: + self.assertEquals(str(e), "java.sql.SQLException: expected") + + def test_sql_exception_on_prepared_execute(self): + cursor = self.conn.cursor() + try: + cursor.execute("dummy stmt ?", (18,)) + except jaydebeapi.DatabaseError as e: + self.assertEquals(str(e), "java.sql.SQLException: expected") + class SqliteTestBase(IntegrationTestBase): def setUpSql(self): From ae4acb64eed9e5862b888b9b808cff62d7a40eea Mon Sep 17 00:00:00 2001 From: tdawber Date: Wed, 28 Dec 2016 12:41:57 +1100 Subject: [PATCH 5/9] add error tests --- test/test_integration.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test_integration.py b/test/test_integration.py index 75d50c6..6074688 100644 --- a/test/test_integration.py +++ b/test/test_integration.py @@ -212,14 +212,14 @@ def test_sql_exception_on_execute(self): try: cursor.execute("dummy stmt") except jaydebeapi.DatabaseError as e: - self.assertEquals(str(e), "java.sql.SQLException: expected") + self.assertEquals(str(e).split(" ")[0], "java.sql.SQLException:") def test_sql_exception_on_prepared_execute(self): cursor = self.conn.cursor() try: cursor.execute("dummy stmt ?", (18,)) except jaydebeapi.DatabaseError as e: - self.assertEquals(str(e), "java.sql.SQLException: expected") + self.assertEquals(str(e).split(" ")[0], "java.sql.SQLException:") class SqliteTestBase(IntegrationTestBase): From e0f076290eaeef366470a7c34b7dff1199c23890 Mon Sep 17 00:00:00 2001 From: tdawber Date: Wed, 28 Dec 2016 12:55:13 +1100 Subject: [PATCH 6/9] add error tests --- test/test_integration.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/test/test_integration.py b/test/test_integration.py index 6074688..9fdf34f 100644 --- a/test/test_integration.py +++ b/test/test_integration.py @@ -214,13 +214,6 @@ def test_sql_exception_on_execute(self): except jaydebeapi.DatabaseError as e: self.assertEquals(str(e).split(" ")[0], "java.sql.SQLException:") - def test_sql_exception_on_prepared_execute(self): - cursor = self.conn.cursor() - try: - cursor.execute("dummy stmt ?", (18,)) - except jaydebeapi.DatabaseError as e: - self.assertEquals(str(e).split(" ")[0], "java.sql.SQLException:") - class SqliteTestBase(IntegrationTestBase): def setUpSql(self): From 6b25213074c06b251ac7ff808e98d87c7e074da6 Mon Sep 17 00:00:00 2001 From: tdawber Date: Wed, 28 Dec 2016 13:16:01 +1100 Subject: [PATCH 7/9] add error tests --- test/test_integration.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/test_integration.py b/test/test_integration.py index 9fdf34f..7a80286 100644 --- a/test/test_integration.py +++ b/test/test_integration.py @@ -18,6 +18,7 @@ # . import jaydebeapi +from jaydebeapi import OperationalError import os import sys @@ -212,7 +213,10 @@ def test_sql_exception_on_execute(self): try: cursor.execute("dummy stmt") except jaydebeapi.DatabaseError as e: + print str(e) self.assertEquals(str(e).split(" ")[0], "java.sql.SQLException:") + except self.conn.OperationalError as e: + self.assertEquals("syntax" in str(e), True) class SqliteTestBase(IntegrationTestBase): From 8f7849a6bd36989d4f8ade3bf8753debb6164f78 Mon Sep 17 00:00:00 2001 From: tdawber Date: Wed, 28 Dec 2016 13:35:36 +1100 Subject: [PATCH 8/9] add error tests --- test/test_integration.py | 1 - 1 file changed, 1 deletion(-) diff --git a/test/test_integration.py b/test/test_integration.py index 7a80286..a1b2389 100644 --- a/test/test_integration.py +++ b/test/test_integration.py @@ -213,7 +213,6 @@ def test_sql_exception_on_execute(self): try: cursor.execute("dummy stmt") except jaydebeapi.DatabaseError as e: - print str(e) self.assertEquals(str(e).split(" ")[0], "java.sql.SQLException:") except self.conn.OperationalError as e: self.assertEquals("syntax" in str(e), True) From e2a1c10f9a760fc119327ece6f96a99fbfa3fe5c Mon Sep 17 00:00:00 2001 From: tdawber Date: Wed, 28 Dec 2016 13:50:42 +1100 Subject: [PATCH 9/9] add error tests --- test/test_mock.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/test_mock.py b/test/test_mock.py index 6dcb702..ffeb979 100644 --- a/test/test_mock.py +++ b/test/test_mock.py @@ -59,6 +59,15 @@ def test_sql_exception_on_execute(self): except jaydebeapi.DatabaseError as e: self.assertEquals(str(e), "java.sql.SQLException: expected") + def test_sql_exception_on_parameter_execute(self): + self.conn.jconn.mockExceptionOnExecute("java.sql.SQLException", "expected") + cursor = self.conn.cursor() + try: + cursor.execute("dummy stmt", (18,)) + fail("expected exception") + except jaydebeapi.DatabaseError as e: + self.assertEquals(str(e), "java.sql.SQLException: expected") + def test_runtime_exception_on_execute(self): self.conn.jconn.mockExceptionOnExecute("java.lang.RuntimeException", "expected") cursor = self.conn.cursor()