Skip to content

Commit 65a1708

Browse files
committed
Add tests for SQL_HANDLE_DESC handle allocation
Co-Authored-By: alinalibq <[email protected]>
1 parent 42f27ab commit 65a1708

File tree

5 files changed

+267
-5
lines changed

5 files changed

+267
-5
lines changed

cpp/src/arrow/flight/sql/odbc/odbc_api.cc

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,6 @@ SQLRETURN SQLAllocHandle(SQLSMALLINT type, SQLHANDLE parent, SQLHANDLE* result)
3939
// GH-47706 TODO: Add tests for SQLAllocStmt, pre-requisite requires
4040
// SQLDriverConnect implementation
4141

42-
// GH-47707 TODO: Add tests for SQL_HANDLE_DESC implementation for
43-
// descriptor handle, pre-requisite requires SQLAllocStmt
44-
4542
*result = nullptr;
4643

4744
switch (type) {
@@ -142,8 +139,6 @@ SQLRETURN SQLFreeHandle(SQLSMALLINT type, SQLHANDLE handle) {
142139
// GH-47706 TODO: Add tests for SQLFreeStmt, pre-requisite requires
143140
// SQLAllocStmt tests
144141

145-
// GH-47707 TODO: Add tests for SQL_HANDLE_DESC implementation for
146-
// descriptor handle
147142
switch (type) {
148143
case SQL_HANDLE_ENV: {
149144
using ODBC::ODBCEnvironment;

cpp/src/arrow/flight/sql/odbc/tests/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ add_arrow_test(flight_sql_odbc_test
3535
odbc_test_suite.cc
3636
odbc_test_suite.h
3737
connection_test.cc
38+
connection_info_test.cc
39+
errors_test.cc
3840
# Enable Protobuf cleanup after test execution
3941
# GH-46889: move protobuf_test_util to a more common location
4042
../../../../engine/substrait/protobuf_test_util.cc
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
#include "arrow/flight/sql/odbc/tests/odbc_test_suite.h"
18+
19+
#include "arrow/flight/sql/odbc/odbc_impl/platform.h"
20+
21+
#include <sql.h>
22+
#include <sqltypes.h>
23+
#include <sqlucode.h>
24+
25+
#include <gtest/gtest.h>
26+
27+
namespace arrow::flight::sql::odbc {
28+
29+
template <typename T>
30+
class ConnectionInfoTest : public T {};
31+
32+
class ConnectionInfoMockTest : public FlightSQLODBCMockTestBase {};
33+
using TestTypes = ::testing::Types<ConnectionInfoMockTest, FlightSQLODBCRemoteTestBase>;
34+
TYPED_TEST_SUITE(ConnectionInfoTest, TestTypes);
35+
// These information types are implemented by the Driver Manager alone.
36+
TYPED_TEST(ConnectionInfoTest, TestSQLGetInfoDriverHdesc) {
37+
SQLHDESC descriptor;
38+
39+
// Allocate a descriptor using alloc handle
40+
ASSERT_EQ(SQL_SUCCESS, SQLAllocHandle(SQL_HANDLE_DESC, this->conn, &descriptor));
41+
42+
// Value returned from driver manager is the desc address
43+
SQLHDESC local_desc = descriptor;
44+
EXPECT_EQ(SQL_SUCCESS, SQLGetInfo(this->conn, SQL_HANDLE_DESC, &local_desc, 0, 0));
45+
EXPECT_GT(local_desc, static_cast<SQLHSTMT>(0));
46+
47+
// Free descriptor handle
48+
ASSERT_EQ(SQL_SUCCESS, SQLFreeHandle(SQL_HANDLE_DESC, descriptor));
49+
}
50+
51+
} // namespace arrow::flight::sql::odbc

cpp/src/arrow/flight/sql/odbc/tests/connection_test.cc

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,4 +220,71 @@ TEST(SQLSetEnvAttr, TestSQLSetEnvAttrNullValuePointer) {
220220
ASSERT_EQ(SQL_SUCCESS, SQLFreeEnv(env));
221221
}
222222

223+
TYPED_TEST(ConnectionTest, TestSQLAllocFreeDesc) {
224+
SQLHDESC descriptor;
225+
226+
// Allocate a descriptor using alloc handle
227+
ASSERT_EQ(SQL_SUCCESS, SQLAllocHandle(SQL_HANDLE_DESC, this->conn, &descriptor));
228+
229+
// Free descriptor handle
230+
ASSERT_EQ(SQL_SUCCESS, SQLFreeHandle(SQL_HANDLE_DESC, descriptor));
231+
}
232+
233+
TYPED_TEST(ConnectionTest, TestSQLSetStmtAttrDescriptor) {
234+
SQLHDESC apd_descriptor, ard_descriptor;
235+
236+
// Allocate an APD descriptor using alloc handle
237+
ASSERT_EQ(SQL_SUCCESS, SQLAllocHandle(SQL_HANDLE_DESC, this->conn, &apd_descriptor));
238+
239+
// Allocate an ARD descriptor using alloc handle
240+
ASSERT_EQ(SQL_SUCCESS, SQLAllocHandle(SQL_HANDLE_DESC, this->conn, &ard_descriptor));
241+
242+
// Save implicitly allocated internal APD and ARD descriptor pointers
243+
SQLPOINTER internal_apd, internal_ard = nullptr;
244+
245+
EXPECT_EQ(SQL_SUCCESS, SQLGetStmtAttr(this->stmt, SQL_ATTR_APP_PARAM_DESC,
246+
&internal_apd, sizeof(internal_apd), 0));
247+
248+
EXPECT_EQ(SQL_SUCCESS, SQLGetStmtAttr(this->stmt, SQL_ATTR_APP_ROW_DESC, &internal_ard,
249+
sizeof(internal_ard), 0));
250+
251+
// Set APD descriptor to explicitly allocated handle
252+
EXPECT_EQ(SQL_SUCCESS, SQLSetStmtAttr(this->stmt, SQL_ATTR_APP_PARAM_DESC,
253+
reinterpret_cast<SQLPOINTER>(apd_descriptor), 0));
254+
255+
// Set ARD descriptor to explicitly allocated handle
256+
EXPECT_EQ(SQL_SUCCESS, SQLSetStmtAttr(this->stmt, SQL_ATTR_APP_ROW_DESC,
257+
reinterpret_cast<SQLPOINTER>(ard_descriptor), 0));
258+
259+
// Verify APD and ARD descriptors are set to explicitly allocated pointers
260+
SQLPOINTER value = nullptr;
261+
EXPECT_EQ(SQL_SUCCESS, SQLGetStmtAttr(this->stmt, SQL_ATTR_APP_PARAM_DESC, &value,
262+
sizeof(value), 0));
263+
264+
EXPECT_EQ(apd_descriptor, value);
265+
266+
EXPECT_EQ(SQL_SUCCESS,
267+
SQLGetStmtAttr(this->stmt, SQL_ATTR_APP_ROW_DESC, &value, sizeof(value), 0));
268+
269+
EXPECT_EQ(ard_descriptor, value);
270+
271+
// Free explicitly allocated APD and ARD descriptor handles
272+
ASSERT_EQ(SQL_SUCCESS, SQLFreeHandle(SQL_HANDLE_DESC, apd_descriptor));
273+
274+
ASSERT_EQ(SQL_SUCCESS, SQLFreeHandle(SQL_HANDLE_DESC, ard_descriptor));
275+
276+
// Verify APD and ARD descriptors has been reverted to implicit descriptors
277+
value = nullptr;
278+
279+
EXPECT_EQ(SQL_SUCCESS, SQLGetStmtAttr(this->stmt, SQL_ATTR_APP_PARAM_DESC, &value,
280+
sizeof(value), 0));
281+
282+
EXPECT_EQ(internal_apd, value);
283+
284+
EXPECT_EQ(SQL_SUCCESS,
285+
SQLGetStmtAttr(this->stmt, SQL_ATTR_APP_ROW_DESC, &value, sizeof(value), 0));
286+
287+
EXPECT_EQ(internal_ard, value);
288+
}
289+
223290
} // namespace arrow::flight::sql::odbc
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
#include "arrow/flight/sql/odbc/tests/odbc_test_suite.h"
18+
19+
#include "arrow/flight/sql/odbc/odbc_impl/platform.h"
20+
21+
#include <sql.h>
22+
#include <sqltypes.h>
23+
#include <sqlucode.h>
24+
25+
#include <gtest/gtest.h>
26+
27+
namespace arrow::flight::sql::odbc {
28+
29+
template <typename T>
30+
class ErrorsTest : public T {};
31+
32+
using TestTypes =
33+
::testing::Types<FlightSQLODBCMockTestBase, FlightSQLODBCRemoteTestBase>;
34+
TYPED_TEST_SUITE(ErrorsTest, TestTypes);
35+
36+
template <typename T>
37+
class ErrorsOdbcV2Test : public T {};
38+
39+
using TestTypesOdbcV2 =
40+
::testing::Types<FlightSQLOdbcV2MockTestBase, FlightSQLOdbcV2RemoteTestBase>;
41+
TYPED_TEST_SUITE(ErrorsOdbcV2Test, TestTypesOdbcV2);
42+
43+
template <typename T>
44+
class ErrorsHandleTest : public T {};
45+
46+
using TestTypesHandle =
47+
::testing::Types<FlightSQLOdbcHandleMockTestBase, FlightSQLOdbcHandleRemoteTestBase>;
48+
TYPED_TEST_SUITE(ErrorsHandleTest, TestTypesHandle);
49+
50+
TYPED_TEST(ErrorsTest, TestSQLGetDiagFieldWForDescriptorFailureFromDriverManager) {
51+
SQLHDESC descriptor;
52+
53+
// Allocate a descriptor using alloc handle
54+
ASSERT_EQ(SQL_SUCCESS, SQLAllocHandle(SQL_HANDLE_DESC, this->conn, &descriptor));
55+
56+
EXPECT_EQ(SQL_ERROR,
57+
SQLGetDescField(descriptor, 1, SQL_DESC_DATETIME_INTERVAL_CODE, 0, 0, 0));
58+
59+
// Retrieve all supported header level and record level data
60+
SQLSMALLINT HEADER_LEVEL = 0;
61+
SQLSMALLINT RECORD_1 = 1;
62+
63+
// SQL_DIAG_NUMBER
64+
SQLINTEGER diag_number;
65+
SQLSMALLINT diag_number_length;
66+
67+
EXPECT_EQ(SQL_SUCCESS,
68+
SQLGetDiagField(SQL_HANDLE_DESC, descriptor, HEADER_LEVEL, SQL_DIAG_NUMBER,
69+
&diag_number, sizeof(SQLINTEGER), &diag_number_length));
70+
71+
EXPECT_EQ(1, diag_number);
72+
73+
// SQL_DIAG_SERVER_NAME
74+
SQLWCHAR server_name[kOdbcBufferSize];
75+
SQLSMALLINT server_name_length;
76+
77+
EXPECT_EQ(SQL_SUCCESS,
78+
SQLGetDiagField(SQL_HANDLE_DESC, descriptor, RECORD_1, SQL_DIAG_SERVER_NAME,
79+
server_name, kOdbcBufferSize, &server_name_length));
80+
81+
// SQL_DIAG_MESSAGE_TEXT
82+
SQLWCHAR message_text[kOdbcBufferSize];
83+
SQLSMALLINT message_text_length;
84+
85+
EXPECT_EQ(SQL_SUCCESS,
86+
SQLGetDiagField(SQL_HANDLE_DESC, descriptor, RECORD_1, SQL_DIAG_MESSAGE_TEXT,
87+
message_text, kOdbcBufferSize, &message_text_length));
88+
89+
EXPECT_GT(message_text_length, 100);
90+
91+
// SQL_DIAG_NATIVE
92+
SQLINTEGER diag_native;
93+
SQLSMALLINT diag_native_length;
94+
95+
EXPECT_EQ(SQL_SUCCESS,
96+
SQLGetDiagField(SQL_HANDLE_DESC, descriptor, RECORD_1, SQL_DIAG_NATIVE,
97+
&diag_native, sizeof(diag_native), &diag_native_length));
98+
99+
EXPECT_EQ(0, diag_native);
100+
101+
// SQL_DIAG_SQLSTATE
102+
const SQLSMALLINT sql_state_size = 6;
103+
SQLWCHAR sql_state[sql_state_size];
104+
SQLSMALLINT sql_state_length;
105+
EXPECT_EQ(
106+
SQL_SUCCESS,
107+
SQLGetDiagField(SQL_HANDLE_DESC, descriptor, RECORD_1, SQL_DIAG_SQLSTATE, sql_state,
108+
sql_state_size * GetSqlWCharSize(), &sql_state_length));
109+
110+
EXPECT_EQ(std::wstring(L"IM001"), std::wstring(sql_state));
111+
112+
// Free descriptor handle
113+
EXPECT_EQ(SQL_SUCCESS, SQLFreeHandle(SQL_HANDLE_DESC, descriptor));
114+
}
115+
116+
TYPED_TEST(ErrorsTest, TestSQLGetDiagRecForDescriptorFailureFromDriverManager) {
117+
SQLHDESC descriptor;
118+
119+
// Allocate a descriptor using alloc handle
120+
ASSERT_EQ(SQL_SUCCESS, SQLAllocHandle(SQL_HANDLE_DESC, this->conn, &descriptor));
121+
122+
EXPECT_EQ(SQL_ERROR,
123+
SQLGetDescField(descriptor, 1, SQL_DESC_DATETIME_INTERVAL_CODE, 0, 0, 0));
124+
125+
SQLWCHAR sql_state[6];
126+
SQLINTEGER native_error;
127+
SQLWCHAR message[kOdbcBufferSize];
128+
SQLSMALLINT message_length;
129+
130+
ASSERT_EQ(SQL_SUCCESS,
131+
SQLGetDiagRec(SQL_HANDLE_DESC, descriptor, 1, sql_state, &native_error,
132+
message, kOdbcBufferSize, &message_length));
133+
134+
EXPECT_GT(message_length, 60);
135+
136+
EXPECT_EQ(0, native_error);
137+
138+
// API not implemented error from driver manager
139+
EXPECT_EQ(std::wstring(L"IM001"), std::wstring(sql_state));
140+
141+
EXPECT_TRUE(!std::wstring(message).empty());
142+
143+
// Free descriptor handle
144+
EXPECT_EQ(SQL_SUCCESS, SQLFreeHandle(SQL_HANDLE_DESC, descriptor));
145+
}
146+
147+
} // namespace arrow::flight::sql::odbc

0 commit comments

Comments
 (0)