Skip to content

Commit

Permalink
Try to make some complex queries work in ODBC backend
Browse files Browse the repository at this point in the history
Describe the statement once again after calling execute() if we had
failed to describe it before because SQLNumResultCols() returned 0, as
it may happen with some complex queries and SQL Server used via ODBC
backend.

Closes #1151.

See #1182.

Co-Authored-By: Vadim Zeitlin <[email protected]>
  • Loading branch information
joshua-vanitha-15639 and vadz committed Nov 17, 2024
1 parent 7fb2e51 commit 48a5a6c
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 0 deletions.
18 changes: 18 additions & 0 deletions src/core/statement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,17 @@ bool statement_impl::execute(bool withDataExchange)

statement_backend::exec_fetch_result res = backEnd_->execute(num);

// another hack related to description: the first call to describe()
// above may not have done anything if we didn't have the correct
// number of columns before calling execute() as happens with at least
// the ODBC backend for some complex queries (see #1151), so call it
// again in this case
if (row_ != NULL && alreadyDescribed_ == false)
{
describe();
define_for_row();
}

bool gotData = false;

if (res == statement_backend::ef_success)
Expand Down Expand Up @@ -708,6 +719,13 @@ void statement_impl::describe()
row_->clean_up();

int const numcols = backEnd_->prepare_for_describe();
if (!numcols)
{
// Return without setting alreadyDescribed_ to true, we'll be called
// again in this case.
return;
}

for (int i = 1; i <= numcols; ++i)
{
db_type dbtype;
Expand Down
62 changes: 62 additions & 0 deletions tests/odbc/test-odbc-mssql.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,68 @@ TEST_CASE("MS SQL long string", "[odbc][mssql][long]")
);
}

TEST_CASE("MS SQL table records count", "[odbc][mssql][count]")
{
soci::session sql(backEnd, connectString);

// Execute the provided SQL query to count records in tables
std::string sql_query = R"(
SET NOCOUNT ON;
DECLARE db_cursor CURSOR FOR
SELECT name FROM sys.databases
WHERE state_desc = 'ONLINE'
AND name IN ('master');
DECLARE @DatabaseName NVARCHAR(128);
DECLARE @outset TABLE(
INSTANCENAME varchar(50),
DATABASENAME varchar(100),
TABLENAME varchar(100),
NUMBEROFRECORDS_I bigint
);
OPEN db_cursor;
FETCH NEXT FROM db_cursor INTO @DatabaseName;
WHILE @@FETCH_STATUS = 0
BEGIN
DECLARE @command nvarchar(1000) = 'USE ' + QUOTENAME(@DatabaseName) +
'; SELECT @@SERVERNAME, DB_NAME(), T.NAME, P.[ROWS] FROM sys.tables T ' +
'INNER JOIN sys.indexes I ON T.OBJECT_ID = I.OBJECT_ID ' +
'INNER JOIN sys.partitions P ON I.OBJECT_ID = P.OBJECT_ID AND I.INDEX_ID = P.INDEX_ID ' +
'INNER JOIN sys.allocation_units A ON P.PARTITION_ID = A.CONTAINER_ID ' +
'WHERE T.NAME NOT LIKE ''DT%'' AND I.OBJECT_ID > 255 AND I.INDEX_ID <= 1 ' +
'GROUP BY T.NAME, I.OBJECT_ID, I.INDEX_ID, I.NAME, P.[ROWS] ' +
'ORDER BY OBJECT_NAME(I.OBJECT_ID)';
INSERT INTO @outset EXEC (@command)
FETCH NEXT FROM db_cursor INTO @DatabaseName
END
CLOSE db_cursor
DEALLOCATE db_cursor
SELECT INSTANCENAME, DATABASENAME, TABLENAME, NUMBEROFRECORDS_I
FROM @outset;
)";

soci::rowset<soci::row> rs = (sql.prepare << sql_query);

// Check that we can access the results.
for (auto it = rs.begin(); it != rs.end(); ++it)
{
soci::row const& row = *it;
std::string instance_name = row.get<std::string>(0);
std::string database_name = row.get<std::string>(1);
std::string table_name = row.get<std::string>(2);
long long number_of_records = row.get<long long>(3);

// Use the variables above to avoid warnings about unused variables and
// check the only one of them that we can be sure about because we have
// "name IN ('master')" in the SQL query above.
INFO("Table " << instance_name << "." << table_name <<
" has " << number_of_records << " records");
CHECK( database_name == "master" );
return;
}

FAIL("No tables found in the master database");
}

// DDL Creation objects for common tests
struct table_creator_one : public table_creator_base
{
Expand Down

0 comments on commit 48a5a6c

Please sign in to comment.