@@ -1722,6 +1722,83 @@ TYPED_TEST(StatementTest, TestSQLBindColIndicatorOnlySQLUnbind) {
17221722 // EXPECT_EQ(1, char_val_ind);
17231723}
17241724
1725+ TYPED_TEST (StatementTest, TestSQLExtendedFetchRowFetching) {
1726+ // Set SQL_ROWSET_SIZE to fetch 3 rows at once
1727+
1728+ constexpr SQLULEN rows = 3 ;
1729+ SQLINTEGER val[rows];
1730+ SQLLEN buf_len = sizeof (val);
1731+ SQLLEN ind[rows];
1732+
1733+ // Same variable will be used for column 1, the value of `val`
1734+ // should be updated after every SQLFetch call.
1735+ ASSERT_EQ (SQL_SUCCESS , SQLBindCol (this ->stmt , 1 , SQL_C_LONG , val, buf_len, ind));
1736+
1737+ ASSERT_EQ (SQL_SUCCESS , SQLSetStmtAttr (this ->stmt , SQL_ROWSET_SIZE ,
1738+ reinterpret_cast <SQLPOINTER >(rows), 0 ));
1739+
1740+ std::wstring wsql =
1741+ LR"(
1742+ SELECT 1 AS small_table
1743+ UNION ALL
1744+ SELECT 2
1745+ UNION ALL
1746+ SELECT 3;
1747+ )" ;
1748+ std::vector<SQLWCHAR > sql0 (wsql.begin (), wsql.end ());
1749+
1750+ ASSERT_EQ (SQL_SUCCESS ,
1751+ SQLExecDirect (this ->stmt , &sql0[0 ], static_cast <SQLINTEGER >(sql0.size ())));
1752+
1753+ // Fetch row 1-3.
1754+ SQLULEN row_count;
1755+ SQLUSMALLINT row_status[rows];
1756+
1757+ ASSERT_EQ (SQL_SUCCESS ,
1758+ SQLExtendedFetch (this ->stmt , SQL_FETCH_NEXT , 0 , &row_count, row_status));
1759+ EXPECT_EQ (3 , row_count);
1760+
1761+ for (int i = 0 ; i < rows; i++) {
1762+ EXPECT_EQ (SQL_SUCCESS , row_status[i]);
1763+ }
1764+
1765+ // Verify 1 is returned for row 1
1766+ EXPECT_EQ (1 , val[0 ]);
1767+ // Verify 2 is returned for row 2
1768+ EXPECT_EQ (2 , val[1 ]);
1769+ // Verify 3 is returned for row 3
1770+ EXPECT_EQ (3 , val[2 ]);
1771+
1772+ // Verify result set has no more data beyond row 3
1773+ SQLULEN row_count2;
1774+ SQLUSMALLINT row_status2[rows];
1775+ EXPECT_EQ (SQL_NO_DATA ,
1776+ SQLExtendedFetch (this ->stmt , SQL_FETCH_NEXT , 0 , &row_count2, row_status2));
1777+ }
1778+
1779+ TEST_F (StatementRemoteTest, DISABLED_TestSQLExtendedFetchQueryNullIndicator) {
1780+ // GH-47110: SQLExtendedFetch should return SQL_SUCCESS_WITH_INFO for 22002
1781+ // Limitation on mock test server prevents null from working properly, so use remote
1782+ // server instead. Mock server has type `DENSE_UNION` for null column data.
1783+ SQLINTEGER val;
1784+
1785+ ASSERT_EQ (SQL_SUCCESS , SQLBindCol (this ->stmt , 1 , SQL_C_LONG , &val, 0 , nullptr ));
1786+
1787+ std::wstring wsql = L" SELECT null as null_col;" ;
1788+ std::vector<SQLWCHAR > sql0 (wsql.begin (), wsql.end ());
1789+
1790+ ASSERT_EQ (SQL_SUCCESS ,
1791+ SQLExecDirect (this ->stmt , &sql0[0 ], static_cast <SQLINTEGER >(sql0.size ())));
1792+
1793+ SQLULEN row_count1;
1794+ SQLUSMALLINT row_status1[1 ];
1795+
1796+ // SQLExtendedFetch should return SQL_SUCCESS_WITH_INFO for 22002 state
1797+ ASSERT_EQ (SQL_SUCCESS_WITH_INFO ,
1798+ SQLExtendedFetch (this ->stmt , SQL_FETCH_NEXT , 0 , &row_count1, row_status1));
1799+ VerifyOdbcErrorState (SQL_HANDLE_STMT , this ->stmt , kErrorState22002 );
1800+ }
1801+
17251802TYPED_TEST (StatementTest, TestSQLNativeSqlReturnsInputString) {
17261803 SQLWCHAR buf[1024 ];
17271804 SQLINTEGER buf_char_len = sizeof (buf) / GetSqlWCharSize ();
0 commit comments