Skip to content

Commit

Permalink
fix(ODBC): MSSQL big string on windows
Browse files Browse the repository at this point in the history
  • Loading branch information
aleks-f committed Nov 9, 2024
1 parent 8ba5a09 commit 2a6bd46
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 52 deletions.
110 changes: 60 additions & 50 deletions Data/ODBC/src/Binder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -526,33 +526,61 @@ void Binder::getColSizeAndPrecision(std::size_t pos,
colSize = 0;
decDigits = 0;

// Not all drivers are equally willing to cooperate in this matter.
// Hence the funky flow control.
if (_pTypeInfo)
// first try to find the actual sizes
try
{
Dynamic::Var tmp;
bool foundSize(false);
bool foundPrec(false);
Parameter p(_rStmt, pos);
colSize = (SQLINTEGER)p.columnSize();
decDigits = (SQLSMALLINT)p.decimalDigits();
}
catch (StatementException&)
{
}

if (!colSize || !decDigits)
{
try
{
ODBCMetaColumn c(_rStmt, pos);
if (!colSize) colSize = (SQLINTEGER)c.length();
if (!decDigits) decDigits = (SQLSMALLINT)c.precision();
}
catch (StatementException&)
{
}
}

if (colSize && decDigits)
return;

// SQLServer driver reports COLUMN_SIZE 8000 for VARCHAR(MAX),
// so the size check must be skipped when big strings are enabled
#ifdef POCO_DATA_ODBC_HAVE_SQL_SERVER_EXT
bool isVarchar(false);
switch (sqlDataType)
{
case SQL_VARCHAR:
case SQL_WVARCHAR:
case SQL_WLONGVARCHAR:
isVarchar = true;
break;
default: break;
}
bool isVarchar(false);
switch (sqlDataType)
{
case SQL_VARCHAR:
case SQL_WVARCHAR:
case SQL_WLONGVARCHAR:
isVarchar = true;
break;
default: break;
}
#endif // POCO_DATA_ODBC_HAVE_SQL_SERVER_EXT

foundSize = _pTypeInfo->tryGetInfo(cDataType, "COLUMN_SIZE", tmp);
if (foundSize) colSize = tmp;
else foundSize = _pTypeInfo->tryGetInfo(sqlDataType, "COLUMN_SIZE", tmp);
if (foundSize) colSize = tmp;
// Not all drivers are equally willing to cooperate in this matter.
// If actual sizes are not found, fail back on the global defaults.
if (_pTypeInfo)
{
Dynamic::Var tmp;

if (!colSize)
{
if (_pTypeInfo->tryGetInfo(cDataType, "COLUMN_SIZE", tmp))
colSize = tmp;
else if (_pTypeInfo->tryGetInfo(sqlDataType, "COLUMN_SIZE", tmp))
colSize = tmp;
}

if (actualSize > static_cast<std::size_t>(colSize)
#ifdef POCO_DATA_ODBC_HAVE_SQL_SERVER_EXT
Expand All @@ -564,39 +592,21 @@ void Binder::getColSizeAndPrecision(std::size_t pos,
__LINE__, pos, actualSize, static_cast<long>(colSize)));
}

foundPrec = _pTypeInfo->tryGetInfo(cDataType, "MAXIMUM_SCALE", tmp);
if (foundPrec) decDigits = tmp;
else foundPrec = _pTypeInfo->tryGetInfo(sqlDataType, "MAXIMUM_SCALE", tmp);
if (foundPrec) decDigits = tmp;

if (foundSize && foundPrec)
return;
}

try
{
Parameter p(_rStmt, pos);
colSize = (SQLINTEGER) p.columnSize();
decDigits = (SQLSMALLINT) p.decimalDigits();
return;
}
catch (StatementException&)
{
}

try
{
ODBCMetaColumn c(_rStmt, pos);
colSize = (SQLINTEGER) c.length();
decDigits = (SQLSMALLINT) c.precision();
return;
}
catch (StatementException&)
{
if (!decDigits)
{
if (_pTypeInfo->tryGetInfo(cDataType, "MAXIMUM_SCALE", tmp))
decDigits = tmp;
else if(_pTypeInfo->tryGetInfo(sqlDataType, "MAXIMUM_SCALE", tmp))
decDigits = tmp;
}
}

// last check, just in case
if ((0 != colSize) && (actualSize > colSize))
if ((0 != colSize) && (actualSize > colSize)
#ifdef POCO_DATA_ODBC_HAVE_SQL_SERVER_EXT
&& !isVarchar
#endif
)
{
throw LengthExceededException(Poco::format("ODBC::Binder::getColSizeAndPrecision();%d: Error binding column %z size=%z, max size=%ld)",
__LINE__, pos, actualSize, static_cast<long>(colSize)));
Expand Down
7 changes: 5 additions & 2 deletions Data/ODBC/src/Utility.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,15 +159,18 @@ void Utility::dateTimeSync(SQL_TIMESTAMP_STRUCT& ts, const Poco::DateTime& dt)

std::string Utility::dbmsName(const ConnectionHandle& db)
{
std::string ret = "unknown"s;
const SQLSMALLINT bufSize = 1024;
SQLCHAR dbmsName[bufSize] = {0};
SQLSMALLINT retSize = 0;
SQLRETURN rc = Poco::Data::ODBC::SQLGetInfo(const_cast<SQLHDBC>(db.handle()), SQL_DBMS_NAME, dbmsName, bufSize, &retSize);
if (!isError(rc))
{
return std::string(reinterpret_cast<char*>(dbmsName), retSize);
ret.assign(reinterpret_cast<char*>(dbmsName), retSize);
// API returns string longer than effective length
ret.erase(ret.find_last_not_of('\0') + 1, std::string::npos);
}
return "unknown"s;
return ret;
}


Expand Down

0 comments on commit 2a6bd46

Please sign in to comment.