baztian / jaydebeapi

JayDeBeApi module allows you to connect from Python code to databases using Java JDBC. It provides a Python DB-API v2.0 to that database.
GNU Lesser General Public License v3.0
365 stars 148 forks source link

Driver throws NPE when None passed as parameter value #244

Closed gordthompson closed 2 days ago

gordthompson commented 5 months ago

(Similar issue to #57.)

Passing None as a parameter value when using the UCanAccess JDBC driver

import jaydebeapi

db_path = "/media/sf_Public/so78458091.accdb"
ucanaccess_jars = [
    "/home/gord/Downloads/JDBC/UCanAccess/ucanaccess-5.0.1.jar",
    "/home/gord/Downloads/JDBC/UCanAccess/lib/commons-lang3-3.8.1.jar",
    "/home/gord/Downloads/JDBC/UCanAccess/lib/commons-logging-1.2.jar",
    "/home/gord/Downloads/JDBC/UCanAccess/lib/hsqldb-2.5.0.jar",
    "/home/gord/Downloads/JDBC/UCanAccess/lib/jackcess-3.0.1.jar",
]
classpath = ":".join(ucanaccess_jars)
cnxn = jaydebeapi.connect(
    "net.ucanaccess.jdbc.UcanaccessDriver",
    f"jdbc:ucanaccess://{db_path};newDatabaseVersion=V2010",
    ["", ""],
    classpath
    )
crsr = cnxn.cursor()

crsr.execute("INSERT INTO my_table (varchar_col) VALUES (?)", (None,))
cnxn.commit()

throws

Traceback (most recent call last):
  File "UcanaccessPreparedStatement.java", line 685, in net.ucanaccess.jdbc.UcanaccessPreparedStatement.setObject
Exception: Java Exception

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/home/gord/venv/df_write.py", line 91, in <module>
    crsr.execute("INSERT INTO my_table (varchar_col) VALUES (?)", (None,))
  File "/home/gord/git/jaydebeapi/jaydebeapi/__init__.py", line 532, in execute
    self._set_stmt_parms(self._prep, parameters)
  File "/home/gord/git/jaydebeapi/jaydebeapi/__init__.py", line 523, in _set_stmt_parms
    prep_stmt.setObject(i + 1, parameters[i])
java.lang.java.lang.NullPointerException: java.lang.NullPointerException

Fix:

@@ -519,8 +519,10 @@ class Cursor(object):
     def _set_stmt_parms(self, prep_stmt, parameters):
         for i in range(len(parameters)):
-            # print (i, parameters[i], type(parameters[i]))
-            prep_stmt.setObject(i + 1, parameters[i])
+            if parameters[i] is None:
+                prep_stmt.setNull(i + 1, 0)  # java.sql.Types.Null
+            else:
+                prep_stmt.setObject(i + 1, parameters[i])

     def execute(self, operation, parameters=None):
         if self._connection._closed:
gordthompson commented 2 days ago

Issue resolved in UCanAccess 5.1.2