Skip to content

Commit c4de836

Browse files
alinaliBQjusting-bq
andcommitted
Extract implementation for SQLGetEnvAttr and SQLSetEnvAttr
Co-authored-by: rscales <[email protected]> Add tests for setting and getting environment attributes Address code review comments Co-Authored-By: justing-bq <[email protected]>
1 parent 1a2a800 commit c4de836

File tree

2 files changed

+207
-4
lines changed

2 files changed

+207
-4
lines changed

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

Lines changed: 93 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -253,16 +253,105 @@ SQLRETURN SQLGetEnvAttr(SQLHENV env, SQLINTEGER attr, SQLPOINTER value_ptr,
253253
ARROW_LOG(DEBUG) << "SQLGetEnvAttr called with env: " << env << ", attr: " << attr
254254
<< ", value_ptr: " << value_ptr << ", buffer_length: " << buffer_length
255255
<< ", str_len_ptr: " << static_cast<const void*>(str_len_ptr);
256-
// GH-46575 TODO: Implement SQLGetEnvAttr
257-
return SQL_INVALID_HANDLE;
256+
257+
using ODBC::ODBCEnvironment;
258+
259+
ODBCEnvironment* environment = reinterpret_cast<ODBCEnvironment*>(env);
260+
261+
return ODBCEnvironment::ExecuteWithDiagnostics(environment, SQL_ERROR, [=]() {
262+
switch (attr) {
263+
case SQL_ATTR_ODBC_VERSION: {
264+
if (!value_ptr && !str_len_ptr) {
265+
throw DriverException("Invalid null pointer for attribute.", "HY000");
266+
}
267+
268+
if (value_ptr) {
269+
SQLINTEGER* value = reinterpret_cast<SQLINTEGER*>(value_ptr);
270+
*value = static_cast<SQLSMALLINT>(environment->GetODBCVersion());
271+
}
272+
273+
if (str_len_ptr) {
274+
*str_len_ptr = sizeof(SQLINTEGER);
275+
}
276+
277+
return SQL_SUCCESS;
278+
}
279+
280+
case SQL_ATTR_OUTPUT_NTS: {
281+
if (!value_ptr && !str_len_ptr) {
282+
throw DriverException("Invalid null pointer for attribute.", "HY000");
283+
}
284+
285+
if (value_ptr) {
286+
// output nts always returns SQL_TRUE
287+
SQLINTEGER* value = reinterpret_cast<SQLINTEGER*>(value_ptr);
288+
*value = SQL_TRUE;
289+
}
290+
291+
if (str_len_ptr) {
292+
*str_len_ptr = sizeof(SQLINTEGER);
293+
}
294+
295+
return SQL_SUCCESS;
296+
}
297+
298+
case SQL_ATTR_CONNECTION_POOLING: {
299+
throw DriverException("Optional feature not supported.", "HYC00");
300+
}
301+
302+
default: {
303+
throw DriverException("Invalid attribute", "HYC00");
304+
}
305+
}
306+
});
258307
}
259308

260309
SQLRETURN SQLSetEnvAttr(SQLHENV env, SQLINTEGER attr, SQLPOINTER value_ptr,
261310
SQLINTEGER str_len) {
262311
ARROW_LOG(DEBUG) << "SQLSetEnvAttr called with env: " << env << ", attr: " << attr
263312
<< ", value_ptr: " << value_ptr << ", str_len: " << str_len;
264-
// GH-46575 TODO: Implement SQLSetEnvAttr
265-
return SQL_INVALID_HANDLE;
313+
314+
using ODBC::ODBCEnvironment;
315+
316+
ODBCEnvironment* environment = reinterpret_cast<ODBCEnvironment*>(env);
317+
318+
return ODBCEnvironment::ExecuteWithDiagnostics(environment, SQL_ERROR, [=]() {
319+
if (!value_ptr) {
320+
throw DriverException("Invalid null pointer for attribute.", "HY024");
321+
}
322+
323+
switch (attr) {
324+
case SQL_ATTR_ODBC_VERSION: {
325+
SQLINTEGER version =
326+
static_cast<SQLINTEGER>(reinterpret_cast<intptr_t>(value_ptr));
327+
if (version == SQL_OV_ODBC2 || version == SQL_OV_ODBC3) {
328+
environment->SetODBCVersion(version);
329+
330+
return SQL_SUCCESS;
331+
} else {
332+
throw DriverException("Invalid value for attribute", "HY024");
333+
}
334+
}
335+
336+
case SQL_ATTR_OUTPUT_NTS: {
337+
// output nts can not be set to SQL_FALSE, is always SQL_TRUE
338+
SQLINTEGER value = static_cast<SQLINTEGER>(reinterpret_cast<intptr_t>(value_ptr));
339+
if (value == SQL_TRUE) {
340+
return SQL_SUCCESS;
341+
} else {
342+
throw DriverException("Invalid value for attribute", "HY024");
343+
}
344+
}
345+
346+
case SQL_ATTR_CONNECTION_POOLING: {
347+
throw DriverException("Optional feature not supported.", "HYC00");
348+
}
349+
350+
default: {
351+
throw DriverException("Invalid attribute", "HY092");
352+
}
353+
}
354+
});
266355
}
267356

268357
SQLRETURN SQLGetConnectAttr(SQLHDBC conn, SQLINTEGER attribute, SQLPOINTER value_ptr,

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

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,4 +106,118 @@ TEST(SQLFreeHandle, TestFreeNullHandles) {
106106
ASSERT_EQ(SQL_INVALID_HANDLE, SQLFreeHandle(SQL_HANDLE_ENV, env));
107107
}
108108

109+
TEST(SQLGetEnvAttr, TestSQLGetEnvAttrODBCVersion) {
110+
SQLHENV env;
111+
112+
SQLINTEGER version;
113+
114+
// Allocate an environment handle
115+
ASSERT_EQ(SQL_SUCCESS, SQLAllocEnv(&env));
116+
117+
ASSERT_EQ(SQL_SUCCESS, SQLGetEnvAttr(env, SQL_ATTR_ODBC_VERSION, &version, 0, 0));
118+
119+
ASSERT_EQ(SQL_OV_ODBC2, version);
120+
121+
ASSERT_EQ(SQL_SUCCESS, SQLFreeEnv(env));
122+
}
123+
124+
TEST(SQLSetEnvAttr, TestSQLSetEnvAttrODBCVersionValid) {
125+
SQLHENV env;
126+
127+
// Allocate an environment handle
128+
ASSERT_EQ(SQL_SUCCESS, SQLAllocEnv(&env));
129+
130+
// Attempt to set to supported version
131+
ASSERT_EQ(SQL_SUCCESS, SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION,
132+
reinterpret_cast<void*>(SQL_OV_ODBC2), 0));
133+
134+
SQLINTEGER version;
135+
// Check ODBC version is set
136+
ASSERT_EQ(SQL_SUCCESS, SQLGetEnvAttr(env, SQL_ATTR_ODBC_VERSION, &version, 0, 0));
137+
138+
ASSERT_EQ(SQL_OV_ODBC2, version);
139+
140+
ASSERT_EQ(SQL_SUCCESS, SQLFreeEnv(env));
141+
}
142+
143+
TEST(SQLSetEnvAttr, TestSQLSetEnvAttrODBCVersionInvalid) {
144+
SQLHENV env;
145+
146+
// Allocate an environment handle
147+
ASSERT_EQ(SQL_SUCCESS, SQLAllocEnv(&env));
148+
149+
// Attempt to set to unsupported version
150+
ASSERT_EQ(SQL_ERROR,
151+
SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, reinterpret_cast<void*>(1), 0));
152+
153+
ASSERT_EQ(SQL_SUCCESS, SQLFreeEnv(env));
154+
}
155+
156+
// GH-46574 TODO: enable TestSQLGetEnvAttrOutputNTS which requires connection support
157+
TYPED_TEST(ConnectionTest, DISABLED_TestSQLGetEnvAttrOutputNTS) {
158+
SQLINTEGER output_nts;
159+
160+
ASSERT_EQ(SQL_SUCCESS,
161+
SQLGetEnvAttr(this->env, SQL_ATTR_OUTPUT_NTS, &output_nts, 0, 0));
162+
163+
ASSERT_EQ(SQL_TRUE, output_nts);
164+
}
165+
166+
TYPED_TEST(ConnectionTest, DISABLED_TestSQLGetEnvAttrGetLength) {
167+
// Test is disabled because call to SQLGetEnvAttr is handled by the driver manager on
168+
// Windows. Windows driver manager ignores the length pointer.
169+
// This test case can be potentially used on macOS/Linux
170+
SQLINTEGER length;
171+
ASSERT_EQ(SQL_SUCCESS,
172+
SQLGetEnvAttr(this->env, SQL_ATTR_ODBC_VERSION, nullptr, 0, &length));
173+
174+
EXPECT_EQ(sizeof(SQLINTEGER), length);
175+
}
176+
177+
TYPED_TEST(ConnectionTest, DISABLED_TestSQLGetEnvAttrNullValuePointer) {
178+
// Test is disabled because call to SQLGetEnvAttr is handled by the driver manager on
179+
// Windows. The Windows driver manager doesn't error out when null pointer is passed.
180+
// This test case can be potentially used on macOS/Linux
181+
ASSERT_EQ(SQL_ERROR,
182+
SQLGetEnvAttr(this->env, SQL_ATTR_ODBC_VERSION, nullptr, 0, nullptr));
183+
}
184+
185+
TEST(SQLSetEnvAttr, TestSQLSetEnvAttrOutputNTSValid) {
186+
SQLHENV env;
187+
188+
// Allocate an environment handle
189+
ASSERT_EQ(SQL_SUCCESS, SQLAllocEnv(&env));
190+
191+
// Attempt to set to output nts to supported version
192+
ASSERT_EQ(SQL_SUCCESS, SQLSetEnvAttr(env, SQL_ATTR_OUTPUT_NTS,
193+
reinterpret_cast<void*>(SQL_TRUE), 0));
194+
195+
ASSERT_EQ(SQL_SUCCESS, SQLFreeEnv(env));
196+
}
197+
198+
TEST(SQLSetEnvAttr, TestSQLSetEnvAttrOutputNTSInvalid) {
199+
SQLHENV env;
200+
201+
// Allocate an environment handle
202+
ASSERT_EQ(SQL_SUCCESS, SQLAllocEnv(&env));
203+
204+
// Attempt to set to output nts to unsupported false
205+
ASSERT_EQ(SQL_ERROR, SQLSetEnvAttr(env, SQL_ATTR_OUTPUT_NTS,
206+
reinterpret_cast<void*>(SQL_FALSE), 0));
207+
208+
ASSERT_EQ(SQL_SUCCESS, SQLFreeEnv(env));
209+
}
210+
211+
TEST(SQLSetEnvAttr, TestSQLSetEnvAttrNullValuePointer) {
212+
SQLHENV env;
213+
214+
// Allocate an environment handle
215+
ASSERT_EQ(SQL_SUCCESS, SQLAllocEnv(&env));
216+
217+
// Attempt to set using bad data pointer
218+
ASSERT_EQ(SQL_ERROR, SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, nullptr, 0));
219+
220+
ASSERT_EQ(SQL_SUCCESS, SQLFreeEnv(env));
221+
}
222+
109223
} // namespace arrow::flight::sql::odbc

0 commit comments

Comments
 (0)