Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cpp/src/arrow/flight/sql/odbc/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ add_arrow_test(flight_sql_odbc_test
columns_test.cc
connection_attr_test.cc
connection_info_test.cc
errors_test.cc
statement_attr_test.cc
statement_test.cc
tables_test.cc
Expand Down
262 changes: 18 additions & 244 deletions cpp/src/arrow/flight/sql/odbc/tests/connection_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,24 @@ TEST(SQLFreeHandle, TestSQLFreeHandleConnect) {
EXPECT_TRUE(return_free_handle == SQL_SUCCESS);
}

TYPED_TEST(FlightSQLODBCTestBase, TestFreeNullHandles) {
// Verifies attempt to free invalid handle does not cause segfault
// Attempt to free null statement handle
SQLRETURN ret = SQLFreeHandle(SQL_HANDLE_STMT, this->stmt);

EXPECT_EQ(ret, SQL_INVALID_HANDLE);

// Attempt to free null connection handle
ret = SQLFreeHandle(SQL_HANDLE_DBC, this->conn);

EXPECT_EQ(ret, SQL_INVALID_HANDLE);

// Attempt to free null environment handle
ret = SQLFreeHandle(SQL_HANDLE_ENV, this->env);

EXPECT_EQ(ret, SQL_INVALID_HANDLE);
}

TEST(SQLFreeConnect, TestSQLFreeConnect) {
// ODBC Environment
SQLHENV env;
Expand Down Expand Up @@ -811,250 +829,6 @@ TEST(SQLDisconnect, TestSQLDisconnectWithoutConnection) {
EXPECT_EQ(ret, SQL_SUCCESS);
}

TYPED_TEST(FlightSQLODBCTestBase, TestSQLGetDiagFieldWForConnectFailure) {

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved these tests to errors_test.cc

// ODBC Environment
SQLHENV env;
SQLHDBC conn;

// Allocate an environment handle
SQLRETURN ret = SQLAllocEnv(&env);

EXPECT_EQ(ret, SQL_SUCCESS);

ret = SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);

EXPECT_EQ(ret, SQL_SUCCESS);

// Allocate a connection using alloc handle
ret = SQLAllocHandle(SQL_HANDLE_DBC, env, &conn);

EXPECT_EQ(ret, SQL_SUCCESS);

// Invalid connect string
std::string connect_str = this->getInvalidConnectionString();

ASSERT_OK_AND_ASSIGN(std::wstring wconnect_str,
arrow::util::UTF8ToWideString(connect_str));
std::vector<SQLWCHAR> connect_str0(wconnect_str.begin(), wconnect_str.end());

SQLWCHAR outstr[ODBC_BUFFER_SIZE];
SQLSMALLINT outstrlen;

// Connecting to ODBC server.
ret = SQLDriverConnect(conn, NULL, &connect_str0[0],
static_cast<SQLSMALLINT>(connect_str0.size()), outstr,
ODBC_BUFFER_SIZE, &outstrlen, SQL_DRIVER_NOPROMPT);

EXPECT_TRUE(ret == SQL_ERROR);

// Retrieve all supported header level and record level data
SQLSMALLINT HEADER_LEVEL = 0;
SQLSMALLINT RECORD_1 = 1;

// SQL_DIAG_NUMBER
SQLINTEGER diag_number;
SQLSMALLINT diag_number_length;

ret = SQLGetDiagField(SQL_HANDLE_DBC, conn, HEADER_LEVEL, SQL_DIAG_NUMBER, &diag_number,
sizeof(SQLINTEGER), &diag_number_length);

EXPECT_EQ(ret, SQL_SUCCESS);

EXPECT_EQ(diag_number, 1);

// SQL_DIAG_SERVER_NAME
SQLWCHAR server_name[ODBC_BUFFER_SIZE];
SQLSMALLINT server_name_length;

ret = SQLGetDiagField(SQL_HANDLE_DBC, conn, RECORD_1, SQL_DIAG_SERVER_NAME, server_name,
ODBC_BUFFER_SIZE, &server_name_length);

EXPECT_EQ(ret, SQL_SUCCESS);

// SQL_DIAG_MESSAGE_TEXT
SQLWCHAR message_text[ODBC_BUFFER_SIZE];
SQLSMALLINT message_text_length;

ret = SQLGetDiagField(SQL_HANDLE_DBC, conn, RECORD_1, SQL_DIAG_MESSAGE_TEXT,
message_text, ODBC_BUFFER_SIZE, &message_text_length);

EXPECT_EQ(ret, SQL_SUCCESS);

EXPECT_GT(message_text_length, 100);

// SQL_DIAG_NATIVE
SQLINTEGER diag_native;
SQLSMALLINT diag_native_length;

ret = SQLGetDiagField(SQL_HANDLE_DBC, conn, RECORD_1, SQL_DIAG_NATIVE, &diag_native,
sizeof(diag_native), &diag_native_length);

EXPECT_EQ(ret, SQL_SUCCESS);

EXPECT_EQ(diag_native, 200);

// SQL_DIAG_SQLSTATE
const SQLSMALLINT sql_state_size = 6;
SQLWCHAR sql_state[sql_state_size];
SQLSMALLINT sql_state_length;
ret = SQLGetDiagField(SQL_HANDLE_DBC, conn, RECORD_1, SQL_DIAG_SQLSTATE, sql_state,
sql_state_size * driver::odbcabstraction::GetSqlWCharSize(),
&sql_state_length);

EXPECT_EQ(ret, SQL_SUCCESS);

// 28000
EXPECT_EQ(sql_state[0], '2');
EXPECT_EQ(sql_state[1], '8');
EXPECT_EQ(sql_state[2], '0');
EXPECT_EQ(sql_state[3], '0');
EXPECT_EQ(sql_state[4], '0');

// Free connection handle
ret = SQLFreeHandle(SQL_HANDLE_DBC, conn);

EXPECT_EQ(ret, SQL_SUCCESS);

// Free environment handle
ret = SQLFreeHandle(SQL_HANDLE_ENV, env);

EXPECT_EQ(ret, SQL_SUCCESS);
}

TYPED_TEST(FlightSQLODBCTestBase, TestSQLGetDiagFieldWForConnectFailureNTS) {
// Test is disabled because driver manager on Windows does not pass through SQL_NTS
// This test case can be potentially used on macOS/Linux
GTEST_SKIP();
// ODBC Environment
SQLHENV env;
SQLHDBC conn;

// Allocate an environment handle
SQLRETURN ret = SQLAllocEnv(&env);

EXPECT_EQ(ret, SQL_SUCCESS);

ret = SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);

EXPECT_EQ(ret, SQL_SUCCESS);

// Allocate a connection using alloc handle
ret = SQLAllocHandle(SQL_HANDLE_DBC, env, &conn);

EXPECT_EQ(ret, SQL_SUCCESS);

// Invalid connect string
std::string connect_str = this->getInvalidConnectionString();

ASSERT_OK_AND_ASSIGN(std::wstring wconnect_str,
arrow::util::UTF8ToWideString(connect_str));
std::vector<SQLWCHAR> connect_str0(wconnect_str.begin(), wconnect_str.end());

SQLWCHAR outstr[ODBC_BUFFER_SIZE];
SQLSMALLINT outstrlen;

// Connecting to ODBC server.
ret = SQLDriverConnect(conn, NULL, &connect_str0[0],
static_cast<SQLSMALLINT>(connect_str0.size()), outstr,
ODBC_BUFFER_SIZE, &outstrlen, SQL_DRIVER_NOPROMPT);

EXPECT_TRUE(ret == SQL_ERROR);

// Retrieve all supported header level and record level data
SQLSMALLINT RECORD_1 = 1;

// SQL_DIAG_MESSAGE_TEXT SQL_NTS
SQLWCHAR message_text[ODBC_BUFFER_SIZE];
SQLSMALLINT message_text_length;

message_text[ODBC_BUFFER_SIZE - 1] = '\0';

ret = SQLGetDiagField(SQL_HANDLE_DBC, conn, RECORD_1, SQL_DIAG_MESSAGE_TEXT,
message_text, SQL_NTS, &message_text_length);

EXPECT_EQ(ret, SQL_SUCCESS);

EXPECT_GT(message_text_length, 100);

// Free connection handle
ret = SQLFreeHandle(SQL_HANDLE_DBC, conn);

EXPECT_EQ(ret, SQL_SUCCESS);

// Free environment handle
ret = SQLFreeHandle(SQL_HANDLE_ENV, env);

EXPECT_EQ(ret, SQL_SUCCESS);
}

TYPED_TEST(FlightSQLODBCTestBase, TestSQLGetDiagRecForConnectFailure) {
// ODBC Environment
SQLHENV env;
SQLHDBC conn;

// Allocate an environment handle
SQLRETURN ret = SQLAllocEnv(&env);

EXPECT_EQ(ret, SQL_SUCCESS);

ret = SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);

EXPECT_EQ(ret, SQL_SUCCESS);

// Allocate a connection using alloc handle
ret = SQLAllocHandle(SQL_HANDLE_DBC, env, &conn);

EXPECT_EQ(ret, SQL_SUCCESS);

// Invalid connect string
std::string connect_str = this->getInvalidConnectionString();

ASSERT_OK_AND_ASSIGN(std::wstring wconnect_str,
arrow::util::UTF8ToWideString(connect_str));
std::vector<SQLWCHAR> connect_str0(wconnect_str.begin(), wconnect_str.end());

SQLWCHAR outstr[ODBC_BUFFER_SIZE];
SQLSMALLINT outstrlen;

// Connecting to ODBC server.
ret = SQLDriverConnect(conn, NULL, &connect_str0[0],
static_cast<SQLSMALLINT>(connect_str0.size()), outstr,
ODBC_BUFFER_SIZE, &outstrlen, SQL_DRIVER_NOPROMPT);

EXPECT_TRUE(ret == SQL_ERROR);

SQLWCHAR sql_state[6];
SQLINTEGER native_error;
SQLWCHAR message[ODBC_BUFFER_SIZE];
SQLSMALLINT message_length;

ret = SQLGetDiagRec(SQL_HANDLE_DBC, conn, 1, sql_state, &native_error, message,
ODBC_BUFFER_SIZE, &message_length);

EXPECT_EQ(ret, SQL_SUCCESS);

EXPECT_GT(message_length, 120);

EXPECT_EQ(native_error, 200);

// 28000
EXPECT_EQ(sql_state[0], '2');
EXPECT_EQ(sql_state[1], '8');
EXPECT_EQ(sql_state[2], '0');
EXPECT_EQ(sql_state[3], '0');
EXPECT_EQ(sql_state[4], '0');

// Free connection handle
ret = SQLFreeHandle(SQL_HANDLE_DBC, conn);

EXPECT_EQ(ret, SQL_SUCCESS);

// Free environment handle
ret = SQLFreeHandle(SQL_HANDLE_ENV, env);

EXPECT_EQ(ret, SQL_SUCCESS);
}

TYPED_TEST(FlightSQLODBCTestBase, TestConnect) {
// Verifies connect and disconnect works on its own
this->connect();
Expand Down
Loading
Loading