Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
9 changes: 1 addition & 8 deletions cpp/src/arrow/flight/sql/odbc/entry_points.cc
Original file line number Diff line number Diff line change
Expand Up @@ -186,14 +186,7 @@ SQLRETURN SQL_API SQLCancel(SQLHSTMT stmt) {
});
}

SQLRETURN SQL_API SQLCloseCursor(SQLHSTMT stmt) {
LOG_DEBUG("SQLCloseCursor called with stmt: {}", stmt);
return ODBC::ODBCStatement::ExecuteWithDiagnostics(stmt, SQL_ERROR, [=]() {
throw driver::odbcabstraction::DriverException("SQLCloseCursor is not implemented",
"IM001");
return SQL_ERROR;
});
}
SQLRETURN SQL_API SQLCloseCursor(SQLHSTMT stmt) { return arrow::SQLCloseCursor(stmt); }

SQLRETURN SQL_API SQLColAttribute(SQLHSTMT stmt, SQLUSMALLINT recordNumber,
SQLUSMALLINT fieldIdentifier,
Expand Down
24 changes: 15 additions & 9 deletions cpp/src/arrow/flight/sql/odbc/odbc_api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -179,12 +179,8 @@ SQLRETURN SQLFreeStmt(SQLHSTMT handle, SQLUSMALLINT option) {
case SQL_CLOSE: {
using ODBC::ODBCStatement;

ODBCStatement* statement = reinterpret_cast<ODBCStatement*>(handle);

return ODBCStatement::ExecuteWithDiagnostics(statement, SQL_ERROR, [=]() {
if (!statement) {
return SQL_INVALID_HANDLE;
}
return ODBCStatement::ExecuteWithDiagnostics(handle, SQL_ERROR, [=]() {
ODBCStatement* statement = reinterpret_cast<ODBCStatement*>(handle);

// Close cursor with suppressErrors set to true
statement->closeCursor(true);
Expand Down Expand Up @@ -1060,6 +1056,19 @@ SQLRETURN SQLBindCol(SQLHSTMT stmt, SQLUSMALLINT recordNumber, SQLSMALLINT cType
});
}

SQLRETURN SQLCloseCursor(SQLHSTMT stmt) {
LOG_DEBUG("SQLCloseCursor called with stmt: {}", stmt);
using ODBC::ODBCStatement;
return ODBCStatement::ExecuteWithDiagnostics(stmt, SQL_ERROR, [=]() {
ODBCStatement* statement = reinterpret_cast<ODBCStatement*>(stmt);

// Close cursor with suppressErrors set to false
statement->closeCursor(false);

return SQL_SUCCESS;
});
}

SQLRETURN SQLGetData(SQLHSTMT stmt, SQLUSMALLINT recordNumber, SQLSMALLINT cType,
SQLPOINTER dataPtr, SQLLEN bufferLength, SQLLEN* indicatorPtr) {
// GH-46979: support SQL_C_GUID data type
Expand All @@ -1080,7 +1089,6 @@ SQLRETURN SQLGetData(SQLHSTMT stmt, SQLUSMALLINT recordNumber, SQLSMALLINT cType

SQLRETURN SQLMoreResults(SQLHSTMT stmt) {
LOG_DEBUG("SQLMoreResults called with stmt: {}", stmt);
// TODO: write tests for SQLMoreResults
using ODBC::ODBCStatement;
// Multiple result sets not supported. Return SQL_NO_DATA by default.
return ODBCStatement::ExecuteWithDiagnostics(stmt, SQL_ERROR, [=]() {
Expand All @@ -1092,7 +1100,6 @@ SQLRETURN SQLMoreResults(SQLHSTMT stmt) {
SQLRETURN SQLNumResultCols(SQLHSTMT stmt, SQLSMALLINT* columnCountPtr) {
LOG_DEBUG("SQLNumResultCols called with stmt: {}, columnCountPtr: {}", stmt,
fmt::ptr(columnCountPtr));
// TODO: write tests for SQLNumResultCols
using ODBC::ODBCStatement;
return ODBCStatement::ExecuteWithDiagnostics(stmt, SQL_ERROR, [=]() {
ODBCStatement* statement = reinterpret_cast<ODBCStatement*>(stmt);
Expand All @@ -1104,7 +1111,6 @@ SQLRETURN SQLNumResultCols(SQLHSTMT stmt, SQLSMALLINT* columnCountPtr) {
SQLRETURN SQLRowCount(SQLHSTMT stmt, SQLLEN* rowCountPtr) {
LOG_DEBUG("SQLRowCount called with stmt: {}, columnCountPtr: {}", stmt,
fmt::ptr(rowCountPtr));
// TODO: write tests for SQLRowCount
using ODBC::ODBCStatement;
return ODBCStatement::ExecuteWithDiagnostics(stmt, SQL_ERROR, [=]() {
ODBCStatement* statement = reinterpret_cast<ODBCStatement*>(stmt);
Expand Down
1 change: 1 addition & 0 deletions cpp/src/arrow/flight/sql/odbc/odbc_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ SQLRETURN SQLExtendedFetch(SQLHSTMT stmt, SQLUSMALLINT fetchOrientation,
SQLRETURN SQLFetchScroll(SQLHSTMT stmt, SQLSMALLINT fetchOrientation, SQLLEN fetchOffset);
SQLRETURN SQLBindCol(SQLHSTMT stmt, SQLUSMALLINT recordNumber, SQLSMALLINT cType,
SQLPOINTER dataPtr, SQLLEN bufferLength, SQLLEN* indicatorPtr);
SQLRETURN SQLCloseCursor(SQLHSTMT stmt);
SQLRETURN SQLGetData(SQLHSTMT stmt, SQLUSMALLINT recordNumber, SQLSMALLINT cType,
SQLPOINTER dataPtr, SQLLEN bufferLength, SQLLEN* indicatorPtr);
SQLRETURN SQLMoreResults(SQLHSTMT stmt);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -703,7 +703,7 @@ void ODBCStatement::RevertAppDescriptor(bool isApd) {

void ODBCStatement::closeCursor(bool suppressErrors) {
if (!suppressErrors && !m_currenResult) {
throw DriverException("Invalid cursor state", "28000");
throw DriverException("Invalid cursor state", "24000");
}

if (m_currenResult) {
Expand Down
60 changes: 60 additions & 0 deletions cpp/src/arrow/flight/sql/odbc/tests/statement_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2470,4 +2470,64 @@ TYPED_TEST(FlightSQLODBCTestBase, SQLNumResultColsFunctionSequenceErrorOnNoQuery
this->disconnect();
}

TYPED_TEST(FlightSQLODBCTestBase, TestSQLFreeStmtSQLClose) {
this->connect();

std::wstring wsql = L"SELECT 1;";
std::vector<SQLWCHAR> sql0(wsql.begin(), wsql.end());

SQLRETURN ret =
SQLExecDirect(this->stmt, &sql0[0], static_cast<SQLINTEGER>(sql0.size()));

EXPECT_EQ(ret, SQL_SUCCESS);

ret = SQLFreeStmt(this->stmt, SQL_CLOSE);

EXPECT_EQ(ret, SQL_SUCCESS);

this->disconnect();
}

TYPED_TEST(FlightSQLODBCTestBase, TestSQLCloseCursor) {
this->connect();

std::wstring wsql = L"SELECT 1;";
std::vector<SQLWCHAR> sql0(wsql.begin(), wsql.end());

SQLRETURN ret =
SQLExecDirect(this->stmt, &sql0[0], static_cast<SQLINTEGER>(sql0.size()));

EXPECT_EQ(ret, SQL_SUCCESS);

ret = SQLCloseCursor(this->stmt);

EXPECT_EQ(ret, SQL_SUCCESS);

this->disconnect();
}

TYPED_TEST(FlightSQLODBCTestBase, TestSQLFreeStmtSQLCloseWithoutCursor) {
// SQLFreeStmt(SQL_CLOSE) does not throw error with invalid cursor
this->connect();

SQLRETURN ret = SQLFreeStmt(this->stmt, SQL_CLOSE);

EXPECT_EQ(ret, SQL_SUCCESS);

this->disconnect();
}

TYPED_TEST(FlightSQLODBCTestBase, TestSQLCloseCursorWithoutCursor) {
this->connect();

SQLRETURN ret = SQLCloseCursor(this->stmt);

EXPECT_EQ(ret, SQL_ERROR);

// Verify invalid cursor error state is returned
VerifyOdbcErrorState(SQL_HANDLE_STMT, this->stmt, error_state_24000);

this->disconnect();
}

} // namespace arrow::flight::sql::odbc
Loading