Skip to content

Commit 77c287e

Browse files
authored
FIX: validate numeric data for range (upper and lower bound) (#77)
[AB#37475](https://sqlclientdrivers.visualstudio.com/c6d89619-62de-46a0-8b46-70b92a84d85e/_workitems/edit/37475) This pull request enhances the `BindParameters` function in `mssql_python/pybind/ddbc_bindings.cpp` by introducing range validation for various parameter types to ensure data integrity and prevent out-of-range errors. Below are the key changes grouped by parameter type: ### Integer Parameter Validations * **Signed 16-bit integer (`short`)**: Added range validation to ensure the value is within the limits of a signed 16-bit integer. Throws an exception if the value is out of range. * **Unsigned 16-bit integer (`unsigned short`)**: Added validation to check that the value does not exceed the maximum limit of an unsigned 16-bit integer. * **Signed 64-bit integer (`int64_t`)**: Introduced range validation to confirm the value is within the bounds of a signed 64-bit integer. * **Unsigned 64-bit integer (`uint64_t`)**: Added a check to ensure the value does not exceed the maximum limit for an unsigned 64-bit integer. ### Date Parameter Validation * **SQL Server Date Range**: Implemented validation for `year` attributes in date parameters to ensure they fall within the valid SQL Server date range (1753-9999). ### Checklist - [x] **Tests Passed** (if applicable) : All pytests passed.
1 parent 05560ef commit 77c287e

File tree

1 file changed

+23
-0
lines changed

1 file changed

+23
-0
lines changed

mssql_python/pybind/ddbc_bindings.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,11 @@ SQLRETURN BindParameters(SQLHANDLE hStmt, const py::list& params,
265265
if (!py::isinstance<py::int_>(param)) {
266266
ThrowStdException(MakeParamMismatchErrorStr(paramInfo.paramCType, paramIndex));
267267
}
268+
int value = param.cast<int>();
269+
// Range validation for signed 16-bit integer
270+
if (value < std::numeric_limits<short>::min() || value > std::numeric_limits<short>::max()) {
271+
ThrowStdException("Signed short integer parameter out of range at paramIndex " + std::to_string(paramIndex));
272+
}
268273
dataPtr =
269274
static_cast<void*>(AllocateParamBuffer<int>(paramBuffers, param.cast<int>()));
270275
break;
@@ -274,6 +279,10 @@ SQLRETURN BindParameters(SQLHANDLE hStmt, const py::list& params,
274279
if (!py::isinstance<py::int_>(param)) {
275280
ThrowStdException(MakeParamMismatchErrorStr(paramInfo.paramCType, paramIndex));
276281
}
282+
unsigned int value = param.cast<unsigned int>();
283+
if (value > std::numeric_limits<unsigned short>::max()) {
284+
ThrowStdException("Unsigned short integer parameter out of range at paramIndex " + std::to_string(paramIndex));
285+
}
277286
dataPtr = static_cast<void*>(
278287
AllocateParamBuffer<unsigned int>(paramBuffers, param.cast<unsigned int>()));
279288
break;
@@ -284,6 +293,11 @@ SQLRETURN BindParameters(SQLHANDLE hStmt, const py::list& params,
284293
if (!py::isinstance<py::int_>(param)) {
285294
ThrowStdException(MakeParamMismatchErrorStr(paramInfo.paramCType, paramIndex));
286295
}
296+
int64_t value = param.cast<int64_t>();
297+
// Range validation for signed 64-bit integer
298+
if (value < std::numeric_limits<int64_t>::min() || value > std::numeric_limits<int64_t>::max()) {
299+
ThrowStdException("Signed 64-bit integer parameter out of range at paramIndex " + std::to_string(paramIndex));
300+
}
287301
dataPtr = static_cast<void*>(
288302
AllocateParamBuffer<int64_t>(paramBuffers, param.cast<int64_t>()));
289303
break;
@@ -293,6 +307,11 @@ SQLRETURN BindParameters(SQLHANDLE hStmt, const py::list& params,
293307
if (!py::isinstance<py::int_>(param)) {
294308
ThrowStdException(MakeParamMismatchErrorStr(paramInfo.paramCType, paramIndex));
295309
}
310+
uint64_t value = param.cast<uint64_t>();
311+
// Range validation for unsigned 64-bit integer
312+
if (value > std::numeric_limits<uint64_t>::max()) {
313+
ThrowStdException("Unsigned 64-bit integer parameter out of range at paramIndex " + std::to_string(paramIndex));
314+
}
296315
dataPtr = static_cast<void*>(
297316
AllocateParamBuffer<uint64_t>(paramBuffers, param.cast<uint64_t>()));
298317
break;
@@ -318,6 +337,10 @@ SQLRETURN BindParameters(SQLHANDLE hStmt, const py::list& params,
318337
if (!py::isinstance(param, dateType)) {
319338
ThrowStdException(MakeParamMismatchErrorStr(paramInfo.paramCType, paramIndex));
320339
}
340+
int year = param.attr("year").cast<int>();
341+
if (year < 1753 || year > 9999) {
342+
ThrowStdException("Date out of range for SQL Server (1753-9999) at paramIndex " + std::to_string(paramIndex));
343+
}
321344
// TODO: can be moved to python by registering SQL_DATE_STRUCT in pybind
322345
SQL_DATE_STRUCT* sqlDatePtr = AllocateParamBuffer<SQL_DATE_STRUCT>(paramBuffers);
323346
sqlDatePtr->year = static_cast<SQLSMALLINT>(param.attr("year").cast<int>());

0 commit comments

Comments
 (0)