-
Notifications
You must be signed in to change notification settings - Fork 16.4k
fix(mysql): handle string typed decimal results #24241
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
14b6155
f5a2f73
1249654
261baf4
12b7452
0f1fd48
9659991
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -314,6 +314,10 @@ class BaseEngineSpec: # pylint: disable=too-many-public-methods | |||||||||||
| # engine-specific type mappings to check prior to the defaults | ||||||||||||
| column_type_mappings: Tuple[ColumnTypeMapping, ...] = () | ||||||||||||
|
|
||||||||||||
| # type-specific functions to mutate values received from the database. | ||||||||||||
| # Needed on certain databases that return values in an unexpected format | ||||||||||||
| column_type_mutators: dict[TypeEngine, Callable[[Any], Any]] = {} | ||||||||||||
|
|
||||||||||||
| # Does database support join-free timeslot grouping | ||||||||||||
| time_groupby_inline = False | ||||||||||||
| limit_method = LimitMethod.FORCE_LIMIT | ||||||||||||
|
|
@@ -737,7 +741,26 @@ def fetch_data( | |||||||||||
| try: | ||||||||||||
| if cls.limit_method == LimitMethod.FETCH_MANY and limit: | ||||||||||||
| return cursor.fetchmany(limit) | ||||||||||||
| return cursor.fetchall() | ||||||||||||
| data = cursor.fetchall() | ||||||||||||
| column_type_mutators = { | ||||||||||||
| row[0]: func | ||||||||||||
| for row in cursor.description | ||||||||||||
| if ( | ||||||||||||
| func := cls.column_type_mutators.get( | ||||||||||||
| type(cls.get_sqla_column_type(cls.get_datatype(row[1]))) | ||||||||||||
| ) | ||||||||||||
| ) | ||||||||||||
| } | ||||||||||||
| if column_type_mutators: | ||||||||||||
|
||||||||||||
| # Peek at the schema to determine which column values, if any, | |
| # require sanitization. | |
| columns_to_sanitize: List[PlacedSanitizeFunc] = _find_columns_to_sanitize( | |
| cursor | |
| ) |
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
|
|
@@ -15,9 +15,12 @@ | |||||||
| # specific language governing permissions and limitations | ||||||||
| # under the License. | ||||||||
| # pylint: disable=unused-argument, import-outside-toplevel, protected-access | ||||||||
| from __future__ import annotations | ||||||||
|
|
||||||||
| import json | ||||||||
| from datetime import datetime | ||||||||
| from typing import Any, Dict, Optional, Type | ||||||||
| from decimal import Decimal | ||||||||
| from typing import Any, Dict, Optional, Type, Union | ||||||||
| from unittest.mock import Mock, patch | ||||||||
|
|
||||||||
| import pandas as pd | ||||||||
|
|
@@ -366,3 +369,37 @@ def test_handle_cursor_early_cancel( | |||||||
| assert cancel_query_mock.call_args[1]["cancel_query_id"] == query_id | ||||||||
| else: | ||||||||
| assert cancel_query_mock.call_args is None | ||||||||
|
|
||||||||
|
|
||||||||
| @pytest.mark.parametrize( | ||||||||
| "data,description,expected_result", | ||||||||
| [ | ||||||||
| ( | ||||||||
| [["1.23456", "abc"]], | ||||||||
| [("dec", "decimal(12,6)"), ("str", "varchar(3)")], | ||||||||
| [(Decimal("1.23456"), "abc")], | ||||||||
|
||||||||
| # only do expensive recasting if datatype is not standard list of tuples | |
| if data and (not isinstance(data, list) or not isinstance(data[0], tuple)): | |
| data = [tuple(row) for row in data] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we add a comment that explains the logic here? This dict comprehension might be hard to understand without the context of this PR