From 4d76b47a3cb9376d5fe0919df1b3d8ff4b96b4ed Mon Sep 17 00:00:00 2001 From: joshua-15639 Date: Tue, 23 Jul 2024 16:55:53 +0530 Subject: [PATCH 1/2] Added tweaks to handle CURSOR/Complex queries --- src/core/statement.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/core/statement.cpp b/src/core/statement.cpp index 49346af0c..c30d07267 100644 --- a/src/core/statement.cpp +++ b/src/core/statement.cpp @@ -318,6 +318,12 @@ bool statement_impl::execute(bool withDataExchange) statement_backend::exec_fetch_result res = backEnd_->execute(num); + // calling describe again in-case it is a complex query and numcols is not populated before execution + if (row_ != NULL && alreadyDescribed_ == false) + { + describe(); + } + bool gotData = false; if (res == statement_backend::ef_success) @@ -714,7 +720,10 @@ void statement_impl::describe() row_->add_properties(props); } - alreadyDescribed_ = true; + if (numcols != 0) + { + alreadyDescribed_ = true; + } } } // namespace details From 8c048a8b78588581cadfa3afc2b85e547ef822b4 Mon Sep 17 00:00:00 2001 From: joshua-15639 Date: Wed, 9 Oct 2024 14:49:42 +0530 Subject: [PATCH 2/2] Added test case to support complex queries --- tests/odbc/test-odbc-mssql.cpp | 60 ++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/tests/odbc/test-odbc-mssql.cpp b/tests/odbc/test-odbc-mssql.cpp index a42393fb9..1c8885a95 100644 --- a/tests/odbc/test-odbc-mssql.cpp +++ b/tests/odbc/test-odbc-mssql.cpp @@ -12,6 +12,7 @@ #include #include #include +#include using namespace soci; using namespace soci::tests; @@ -75,6 +76,65 @@ 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 rs = (sql.prepare << sql_query); + + // Iterate over the results and print them (or check them in an actual test case) + for (auto it = rs.begin(); it != rs.end(); ++it) + { + soci::row const& row = *it; + std::string instance_name = row.get(0); + std::string database_name = row.get(1); + std::string table_name = row.get(2); + long long number_of_records = row.get(3); + + std::cout << "Instance: " << instance_name + << ", Database: " << database_name + << ", Table: " << table_name + << ", Records: " << number_of_records << std::endl; + + // Here you can add checks to validate the expected values. + } +} + // DDL Creation objects for common tests struct table_creator_one : public table_creator_base {