@@ -37,6 +37,100 @@ class StatementRemoteTest : public FlightSQLODBCRemoteTestBase {};
3737using TestTypes = ::testing::Types<StatementMockTest, StatementRemoteTest>;
3838TYPED_TEST_SUITE (StatementTest, TestTypes);
3939
40+ TYPED_TEST (StatementTest, TestSQLFetchScrollRowFetching) {
41+ SQLLEN rows_fetched;
42+ SQLSetStmtAttr (this ->stmt , SQL_ATTR_ROWS_FETCHED_PTR, &rows_fetched, 0 );
43+
44+ std::wstring wsql =
45+ LR"(
46+ SELECT 1 AS small_table
47+ UNION ALL
48+ SELECT 2
49+ UNION ALL
50+ SELECT 3;
51+ )" ;
52+ std::vector<SQLWCHAR> sql0 (wsql.begin (), wsql.end ());
53+
54+ ASSERT_EQ (SQL_SUCCESS,
55+ SQLExecDirect (this ->stmt , &sql0[0 ], static_cast <SQLINTEGER>(sql0.size ())));
56+
57+ // Fetch row 1
58+ ASSERT_EQ (SQL_SUCCESS, SQLFetchScroll (this ->stmt , SQL_FETCH_NEXT, 0 ));
59+
60+ SQLINTEGER val;
61+ SQLLEN buf_len = sizeof (val);
62+ SQLLEN ind;
63+
64+ ASSERT_EQ (SQL_SUCCESS, SQLGetData (this ->stmt , 1 , SQL_C_LONG, &val, buf_len, &ind));
65+ // Verify 1 is returned
66+ EXPECT_EQ (1 , val);
67+ // Verify 1 row is fetched
68+ EXPECT_EQ (1 , rows_fetched);
69+
70+ // Fetch row 2
71+ ASSERT_EQ (SQL_SUCCESS, SQLFetchScroll (this ->stmt , SQL_FETCH_NEXT, 0 ));
72+
73+ ASSERT_EQ (SQL_SUCCESS, SQLGetData (this ->stmt , 1 , SQL_C_LONG, &val, buf_len, &ind));
74+
75+ // Verify 2 is returned
76+ EXPECT_EQ (2 , val);
77+ // Verify 1 row is fetched in the last SQLFetchScroll call
78+ EXPECT_EQ (1 , rows_fetched);
79+
80+ // Fetch row 3
81+ ASSERT_EQ (SQL_SUCCESS, SQLFetchScroll (this ->stmt , SQL_FETCH_NEXT, 0 ));
82+
83+ ASSERT_EQ (SQL_SUCCESS, SQLGetData (this ->stmt , 1 , SQL_C_LONG, &val, buf_len, &ind));
84+
85+ // Verify 3 is returned
86+ EXPECT_EQ (3 , val);
87+ // Verify 1 row is fetched in the last SQLFetchScroll call
88+ EXPECT_EQ (1 , rows_fetched);
89+
90+ // Verify result set has no more data beyond row 3
91+ ASSERT_EQ (SQL_NO_DATA, SQLFetchScroll (this ->stmt , SQL_FETCH_NEXT, 0 ));
92+
93+ ASSERT_EQ (SQL_ERROR, SQLGetData (this ->stmt , 1 , SQL_C_LONG, &val, 0 , &ind));
94+ // Invalid cursor state
95+ VerifyOdbcErrorState (SQL_HANDLE_STMT, this ->stmt , kErrorState24000 );
96+ }
97+
98+ TYPED_TEST (StatementTest, TestSQLFetchScrollUnsupportedOrientation) {
99+ // SQL_FETCH_PRIOR is the only supported fetch orientation.
100+
101+ std::wstring wsql = L" SELECT 1;" ;
102+ std::vector<SQLWCHAR> sql0 (wsql.begin (), wsql.end ());
103+
104+ ASSERT_EQ (SQL_SUCCESS,
105+ SQLExecDirect (this ->stmt , &sql0[0 ], static_cast <SQLINTEGER>(sql0.size ())));
106+
107+ ASSERT_EQ (SQL_ERROR, SQLFetchScroll (this ->stmt , SQL_FETCH_PRIOR, 0 ));
108+
109+ VerifyOdbcErrorState (SQL_HANDLE_STMT, this ->stmt , kErrorStateHYC00 );
110+
111+ SQLLEN fetch_offset = 1 ;
112+ ASSERT_EQ (SQL_ERROR, SQLFetchScroll (this ->stmt , SQL_FETCH_RELATIVE, fetch_offset));
113+
114+ VerifyOdbcErrorState (SQL_HANDLE_STMT, this ->stmt , kErrorStateHYC00 );
115+
116+ ASSERT_EQ (SQL_ERROR, SQLFetchScroll (this ->stmt , SQL_FETCH_ABSOLUTE, fetch_offset));
117+
118+ VerifyOdbcErrorState (SQL_HANDLE_STMT, this ->stmt , kErrorStateHYC00 );
119+
120+ ASSERT_EQ (SQL_ERROR, SQLFetchScroll (this ->stmt , SQL_FETCH_FIRST, 0 ));
121+
122+ VerifyOdbcErrorState (SQL_HANDLE_STMT, this ->stmt , kErrorStateHYC00 );
123+
124+ ASSERT_EQ (SQL_ERROR, SQLFetchScroll (this ->stmt , SQL_FETCH_LAST, 0 ));
125+
126+ VerifyOdbcErrorState (SQL_HANDLE_STMT, this ->stmt , kErrorStateHYC00 );
127+
128+ ASSERT_EQ (SQL_ERROR, SQLFetchScroll (this ->stmt , SQL_FETCH_BOOKMARK, fetch_offset));
129+
130+ // ODBC Driver Manager returns state HY106 for SQL_FETCH_BOOKMARK
131+ VerifyOdbcErrorState (SQL_HANDLE_STMT, this ->stmt , kErrorStateHY106 );
132+ }
133+
40134TYPED_TEST (StatementTest, TestSQLNativeSqlReturnsInputString) {
41135 SQLWCHAR buf[1024 ];
42136 SQLINTEGER buf_char_len = sizeof (buf) / ODBC::GetSqlWCharSize ();
0 commit comments