Skip to content

Commit d844cfe

Browse files
authored
FIX: Fixed and Added tests for Type Inference Bug (#252)
### Work Item / Issue Reference <!-- IMPORTANT: Please follow the PR template guidelines below. For mssql-python maintainers: Insert your ADO Work Item ID below (e.g. AB#37452) For external contributors: Insert Github Issue number below (e.g. #149) Only one reference is required - either GitHub issue OR ADO Work Item. --> <!-- mssql-python maintainers: ADO Work Item --> > AB#<WORK_ITEM_ID> <!-- External contributors: GitHub Issue --> > GitHub Issue: #253 ------------------------------------------------------------------- ### Summary <!-- Insert your summary of changes below. Minimum 10 characters required. --> This pull request removes the `_select_best_sample_value` static method and updates how sample values are selected for type inference in the `executemany` method. Instead of using the old method, the code now relies on `_compute_column_type` to determine sample values and type information. **Refactoring and Type Inference Updates:** * Removed the `_select_best_sample_value` static method from `cursor.py`, consolidating the logic for type inference. * Updated the `executemany` method to use `_compute_column_type` for determining sample values, minimum, and maximum values for each column, improving clarity and maintainability. <!-- ### PR Title Guide > For feature requests FEAT: (short-description) > For non-feature requests like test case updates, config updates , dependency updates etc CHORE: (short-description) > For Fix requests FIX: (short-description) > For doc update requests DOC: (short-description) > For Formatting, indentation, or styling update STYLE: (short-description) > For Refactor, without any feature changes REFACTOR: (short-description) > For release related changes, without any feature changes RELEASE: #<RELEASE_VERSION> (short-description) ### Contribution Guidelines External contributors: - Create a GitHub issue first: https://github.com/microsoft/mssql-python/issues/new - Link the GitHub issue in the "GitHub Issue" section above - Follow the PR title format and provide a meaningful summary mssql-python maintainers: - Create an ADO Work Item following internal processes - Link the ADO Work Item in the "ADO Work Item" section above - Follow the PR title format and provide a meaningful summary -->
1 parent 7598b35 commit d844cfe

File tree

2 files changed

+113
-0
lines changed

2 files changed

+113
-0
lines changed

mssql_python/cursor.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1613,6 +1613,7 @@ def executemany(self, operation: str, seq_of_parameters: list) -> None:
16131613
# Use auto-detection for columns without explicit types
16141614
column = [row[col_index] for row in seq_of_parameters] if hasattr(seq_of_parameters, '__getitem__') else []
16151615
sample_value, min_val, max_val = self._compute_column_type(column)
1616+
16161617
dummy_row = list(sample_row)
16171618
paraminfo = self._create_parameter_types_list(
16181619
sample_value, param_info, dummy_row, col_index, min_val=min_val, max_val=max_val

tests/test_004_cursor.py

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1262,6 +1262,118 @@ def test_executemany_binary_data_edge_cases(cursor, db_connection):
12621262
cursor.execute("DROP TABLE IF EXISTS #pytest_binary_test")
12631263
db_connection.commit()
12641264

1265+
def test_executemany_mixed_ints(cursor, db_connection):
1266+
"""Test executemany with mixed positive and negative integers."""
1267+
try:
1268+
cursor.execute("CREATE TABLE #pytest_mixed_ints (val INT)")
1269+
data = [(1,), (-5,), (3,)]
1270+
cursor.executemany("INSERT INTO #pytest_mixed_ints VALUES (?)", data)
1271+
db_connection.commit()
1272+
1273+
cursor.execute("SELECT val FROM #pytest_mixed_ints ORDER BY val")
1274+
results = [row[0] for row in cursor.fetchall()]
1275+
assert sorted(results) == [-5, 1, 3]
1276+
finally:
1277+
cursor.execute("DROP TABLE IF EXISTS #pytest_mixed_ints")
1278+
db_connection.commit()
1279+
1280+
1281+
def test_executemany_int_edge_cases(cursor, db_connection):
1282+
"""Test executemany with very large and very small integers."""
1283+
try:
1284+
cursor.execute("CREATE TABLE #pytest_int_edges (val BIGINT)")
1285+
data = [(0,), (2**31-1,), (-2**31,), (2**63-1,), (-2**63,)]
1286+
cursor.executemany("INSERT INTO #pytest_int_edges VALUES (?)", data)
1287+
db_connection.commit()
1288+
1289+
cursor.execute("SELECT val FROM #pytest_int_edges ORDER BY val")
1290+
results = [row[0] for row in cursor.fetchall()]
1291+
assert results == sorted([0, 2**31-1, -2**31, 2**63-1, -2**63])
1292+
finally:
1293+
cursor.execute("DROP TABLE IF EXISTS #pytest_int_edges")
1294+
db_connection.commit()
1295+
1296+
1297+
def test_executemany_bools_and_ints(cursor, db_connection):
1298+
"""Test executemany with mix of booleans and integers."""
1299+
try:
1300+
cursor.execute("CREATE TABLE #pytest_bool_int (val INT)")
1301+
data = [(True,), (False,), (2,)]
1302+
cursor.executemany("INSERT INTO #pytest_bool_int VALUES (?)", data)
1303+
db_connection.commit()
1304+
1305+
cursor.execute("SELECT val FROM #pytest_bool_int ORDER BY val")
1306+
results = [row[0] for row in cursor.fetchall()]
1307+
# True -> 1, False -> 0
1308+
assert results == [0, 1, 2]
1309+
finally:
1310+
cursor.execute("DROP TABLE IF EXISTS #pytest_bool_int")
1311+
db_connection.commit()
1312+
1313+
1314+
def test_executemany_ints_with_none(cursor, db_connection):
1315+
"""Test executemany with integers and None values."""
1316+
try:
1317+
cursor.execute("CREATE TABLE #pytest_int_none (val INT)")
1318+
data = [(1,), (None,), (3,)]
1319+
cursor.executemany("INSERT INTO #pytest_int_none VALUES (?)", data)
1320+
db_connection.commit()
1321+
1322+
cursor.execute("SELECT val FROM #pytest_int_none ORDER BY val")
1323+
results = [row[0] for row in cursor.fetchall()]
1324+
assert results.count(None) == 1
1325+
assert results.count(1) == 1
1326+
assert results.count(3) == 1
1327+
finally:
1328+
cursor.execute("DROP TABLE IF EXISTS #pytest_int_none")
1329+
db_connection.commit()
1330+
1331+
1332+
def test_executemany_strings_of_various_lengths(cursor, db_connection):
1333+
"""Test executemany with strings of different lengths."""
1334+
try:
1335+
cursor.execute("CREATE TABLE #pytest_varied_strings (val NVARCHAR(50))")
1336+
data = [("a",), ("abcd",), ("abc",)]
1337+
cursor.executemany("INSERT INTO #pytest_varied_strings VALUES (?)", data)
1338+
db_connection.commit()
1339+
1340+
cursor.execute("SELECT val FROM #pytest_varied_strings ORDER BY val")
1341+
results = [row[0] for row in cursor.fetchall()]
1342+
assert sorted(results) == ["a", "abc", "abcd"]
1343+
finally:
1344+
cursor.execute("DROP TABLE IF EXISTS #pytest_varied_strings")
1345+
db_connection.commit()
1346+
1347+
1348+
def test_executemany_bytes_values(cursor, db_connection):
1349+
"""Test executemany with bytes values."""
1350+
try:
1351+
cursor.execute("CREATE TABLE #pytest_bytes (val VARBINARY(50))")
1352+
data = [(b"a",), (b"abcdef",)]
1353+
cursor.executemany("INSERT INTO #pytest_bytes VALUES (?)", data)
1354+
db_connection.commit()
1355+
1356+
cursor.execute("SELECT val FROM #pytest_bytes ORDER BY val")
1357+
results = [row[0] for row in cursor.fetchall()]
1358+
assert results == [b"a", b"abcdef"]
1359+
finally:
1360+
cursor.execute("DROP TABLE IF EXISTS #pytest_bytes")
1361+
db_connection.commit()
1362+
1363+
def test_executemany_empty_parameter_list(cursor, db_connection):
1364+
"""Test executemany with an empty parameter list."""
1365+
try:
1366+
cursor.execute("CREATE TABLE #pytest_empty_params (val INT)")
1367+
data = []
1368+
cursor.executemany("INSERT INTO #pytest_empty_params VALUES (?)", data)
1369+
db_connection.commit()
1370+
1371+
cursor.execute("SELECT COUNT(*) FROM #pytest_empty_params")
1372+
count = cursor.fetchone()[0]
1373+
assert count == 0
1374+
finally:
1375+
cursor.execute("DROP TABLE IF EXISTS #pytest_empty_params")
1376+
db_connection.commit()
12651377

12661378
def test_nextset(cursor):
12671379
"""Test nextset"""

0 commit comments

Comments
 (0)