Skip to content

Commit

Permalink
Bugfix for prepared statements send the wrong types as parameters to …
Browse files Browse the repository at this point in the history
…the server (#354)

* Re-enable test for GitHub issue #341
* Fix failing tests from GitHub Issue-341
* Update lock file

---------
Co-authored-by: Torsten Kilias <[email protected]>
  • Loading branch information
Nicoretti authored Jun 28, 2023
1 parent 674a3e7 commit 4b12ad0
Show file tree
Hide file tree
Showing 4 changed files with 490 additions and 290 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
Unreleased
==========

🐞 Fixed
---------

- Fixed `prepared statements send the wrong types as parameters to the server <https://github.com/exasol/sqlalchemy-exasol/issues/341>`_

.. _changelog-4.5.1:

4.5.1 — 2023-05-25
Expand Down
60 changes: 59 additions & 1 deletion exasol/driver/websocket/_cursor.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
"""
import datetime
import decimal
import time
from collections import defaultdict
from dataclasses import (
astuple,
Expand Down Expand Up @@ -231,6 +230,59 @@ def execute(self, operation, parameters=None):
except pyexasol.exceptions.ExaError as ex:
raise Error() from ex

@staticmethod
def _adapt_to_requested_db_types(parameters, db_response):
"""
Adapt parameter types to match the types requested by the DB in the
`createPreparedStatement <https://github.com/exasol/websocket-api/blob/master/docs/commands/createPreparedStatementV1.md>`_
response.
Args:
parameters: which will be passed/send to the database.
db_response: contains the DB response including the required types.
Attention:
This shim method currently only patches the following types:
* VARCHAR
* DOUBLE
therefore it the future it may be necessary to improve or extend this.
A hint that patching of a specific type is required, could be and
error message similar to this one:
.. code-block::
pyexasol.exceptions.ExaRequestError:
...
message => getString: JSON value is not a string. (...)
...
"""

def varchar(value):
if value is None:
return None
return str(value)

def double(value):
if value is None:
return None
return float(value)

converters = defaultdict(
lambda: _identity, {"VARCHAR": varchar, "DOUBLE": double}
)
selected_converters = (
converters[column["dataType"]["type"]] for column in db_response["columns"]
)
parameters = zip(selected_converters, parameters)
parameters = [converter(value) for converter, value in parameters]
return parameters

@_is_not_closed
def executemany(self, operation, seq_of_parameters):
"""See also :py:meth: `Cursor.executemany`"""
Expand All @@ -239,6 +291,12 @@ def executemany(self, operation, seq_of_parameters):
]
connection = self._connection.connection
self._cursor = connection.cls_statement(connection, operation, prepare=True)

parameter_data = self._cursor.parameter_data
parameters = [
Cursor._adapt_to_requested_db_types(params, parameter_data)
for params in parameters
]
try:
self._cursor.execute_prepared(parameters)
except pyexasol.exceptions.ExaError as ex:
Expand Down
Loading

0 comments on commit 4b12ad0

Please sign in to comment.