diff --git a/jaydebeapi/__init__.py b/jaydebeapi/__init__.py index 51c2b84..8c244fe 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 @@ -470,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() 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() { diff --git a/test/test_integration.py b/test/test_integration.py index 42b6117..a1b2389 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 @@ -207,6 +208,15 @@ 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).split(" ")[0], "java.sql.SQLException:") + except self.conn.OperationalError as e: + self.assertEquals("syntax" in str(e), True) + class SqliteTestBase(IntegrationTestBase): def setUpSql(self): 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()