diff --git a/cpp/src/arrow/flight/sql/odbc/flight_sql/flight_sql_result_set_metadata.cc b/cpp/src/arrow/flight/sql/odbc/flight_sql/flight_sql_result_set_metadata.cc index 0fa6b03c4a7e..06a56921f8d2 100644 --- a/cpp/src/arrow/flight/sql/odbc/flight_sql/flight_sql_result_set_metadata.cc +++ b/cpp/src/arrow/flight/sql/odbc/flight_sql/flight_sql_result_set_metadata.cc @@ -213,11 +213,14 @@ size_t FlightSqlResultSetMetadata::GetOctetLength(int column_position) { .value_or(DefaultLengthForVariableLengthColumns); } -std::string FlightSqlResultSetMetadata::GetTypeName(int column_position) { +std::string FlightSqlResultSetMetadata::GetTypeName(int column_position, int data_type) { arrow::flight::sql::ColumnMetadata metadata = GetMetadata(schema_->field(column_position - 1)); - return metadata.GetTypeName().ValueOrElse([] { return ""; }); + return metadata.GetTypeName().ValueOrElse([data_type] { + // If we get an empty type name, figure out the type name from the data_type. + return driver::flight_sql::GetTypeNameFromSqlDataType(data_type); + }); } driver::odbcabstraction::Updatability FlightSqlResultSetMetadata::GetUpdatable( diff --git a/cpp/src/arrow/flight/sql/odbc/flight_sql/flight_sql_result_set_metadata.h b/cpp/src/arrow/flight/sql/odbc/flight_sql/flight_sql_result_set_metadata.h index 29901652c521..cd990b108868 100644 --- a/cpp/src/arrow/flight/sql/odbc/flight_sql/flight_sql_result_set_metadata.h +++ b/cpp/src/arrow/flight/sql/odbc/flight_sql/flight_sql_result_set_metadata.h @@ -79,7 +79,7 @@ class FlightSqlResultSetMetadata : public odbcabstraction::ResultSetMetadata { size_t GetOctetLength(int column_position) override; - std::string GetTypeName(int column_position) override; + std::string GetTypeName(int column_position, int data_type) override; odbcabstraction::Updatability GetUpdatable(int column_position) override; diff --git a/cpp/src/arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/spi/result_set_metadata.h b/cpp/src/arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/spi/result_set_metadata.h index 636dce21e4a7..c8bab9c19529 100644 --- a/cpp/src/arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/spi/result_set_metadata.h +++ b/cpp/src/arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/spi/result_set_metadata.h @@ -144,7 +144,7 @@ class ResultSetMetadata { /// \brief It returns the data type as a string. /// \param column_position [in] the position of the column, starting from 1. /// \return the data type string. - virtual std::string GetTypeName(int column_position) = 0; + virtual std::string GetTypeName(int column_position, int data_type) = 0; /// \brief It returns a numeric values indicate the updatability of the /// column. diff --git a/cpp/src/arrow/flight/sql/odbc/odbcabstraction/odbc_impl/odbc_descriptor.cc b/cpp/src/arrow/flight/sql/odbc/odbcabstraction/odbc_impl/odbc_descriptor.cc index 97b31bb550e6..0548760702c9 100644 --- a/cpp/src/arrow/flight/sql/odbc/odbcabstraction/odbc_impl/odbc_descriptor.cc +++ b/cpp/src/arrow/flight/sql/odbc/odbcabstraction/odbc_impl/odbc_descriptor.cc @@ -482,6 +482,8 @@ void ODBCDescriptor::PopulateFromResultSetMetadata(ResultSetMetadata* rsmd) { for (size_t i = 0; i < m_records.size(); ++i) { size_t oneBasedIndex = i + 1; + int16_t concise_type = rsmd->GetConciseType(oneBasedIndex); + m_records[i].m_baseColumnName = rsmd->GetBaseColumnName(oneBasedIndex); m_records[i].m_baseTableName = rsmd->GetBaseTableName(oneBasedIndex); m_records[i].m_catalogName = rsmd->GetCatalogName(oneBasedIndex); @@ -492,9 +494,8 @@ void ODBCDescriptor::PopulateFromResultSetMetadata(ResultSetMetadata* rsmd) { m_records[i].m_name = rsmd->GetName(oneBasedIndex); m_records[i].m_schemaName = rsmd->GetSchemaName(oneBasedIndex); m_records[i].m_tableName = rsmd->GetTableName(oneBasedIndex); - m_records[i].m_typeName = rsmd->GetTypeName(oneBasedIndex); - m_records[i].m_conciseType = - GetSqlTypeForODBCVersion(rsmd->GetConciseType(oneBasedIndex), m_is2xConnection); + m_records[i].m_typeName = rsmd->GetTypeName(oneBasedIndex, concise_type); + m_records[i].m_conciseType = GetSqlTypeForODBCVersion(concise_type, m_is2xConnection); m_records[i].m_dataPtr = nullptr; m_records[i].m_indicatorPtr = nullptr; m_records[i].m_displaySize = rsmd->GetColumnDisplaySize(oneBasedIndex); diff --git a/cpp/src/arrow/flight/sql/odbc/tests/columns_test.cc b/cpp/src/arrow/flight/sql/odbc/tests/columns_test.cc index 25b8b51bd47b..a4abad2eafd6 100644 --- a/cpp/src/arrow/flight/sql/odbc/tests/columns_test.cc +++ b/cpp/src/arrow/flight/sql/odbc/tests/columns_test.cc @@ -286,14 +286,18 @@ void checkSQLColAttributes(SQLHSTMT stmt, SQLUSMALLINT idx, void checkSQLColAttributeString(SQLHSTMT stmt, const std::wstring& wsql, SQLUSMALLINT idx, SQLUSMALLINT fieldIdentifier, const std::wstring& expectedAttrString) { - // Execute query and check SQLColAttribute string attribute - std::vector sql0(wsql.begin(), wsql.end()); - SQLRETURN ret = SQLExecDirect(stmt, &sql0[0], static_cast(sql0.size())); - EXPECT_EQ(ret, SQL_SUCCESS); + SQLRETURN ret; + if (!wsql.empty()) { + // Execute query + std::vector sql0(wsql.begin(), wsql.end()); + ret = SQLExecDirect(stmt, &sql0[0], static_cast(sql0.size())); + EXPECT_EQ(ret, SQL_SUCCESS); - ret = SQLFetch(stmt); - EXPECT_EQ(ret, SQL_SUCCESS); + ret = SQLFetch(stmt); + EXPECT_EQ(ret, SQL_SUCCESS); + } + // check SQLColAttribute string attribute std::vector strVal(ODBC_BUFFER_SIZE); SQLSMALLINT strLen = 0; @@ -326,14 +330,18 @@ void checkSQLColAttributeNumeric(SQLHSTMT stmt, const std::wstring& wsql, void checkSQLColAttributesString(SQLHSTMT stmt, const std::wstring& wsql, SQLUSMALLINT idx, SQLUSMALLINT fieldIdentifier, const std::wstring& expectedAttrString) { - // Execute query and check ODBC 2.0 API SQLColAttributes string attribute - std::vector sql0(wsql.begin(), wsql.end()); - SQLRETURN ret = SQLExecDirect(stmt, &sql0[0], static_cast(sql0.size())); - EXPECT_EQ(ret, SQL_SUCCESS); + SQLRETURN ret; + if (!wsql.empty()) { + // Execute query + std::vector sql0(wsql.begin(), wsql.end()); + ret = SQLExecDirect(stmt, &sql0[0], static_cast(sql0.size())); + EXPECT_EQ(ret, SQL_SUCCESS); - ret = SQLFetch(stmt); - EXPECT_EQ(ret, SQL_SUCCESS); + ret = SQLFetch(stmt); + EXPECT_EQ(ret, SQL_SUCCESS); + } + // check ODBC 2.0 API SQLColAttributes string attribute std::vector strVal(ODBC_BUFFER_SIZE); SQLSMALLINT strLen = 0; @@ -2247,8 +2255,14 @@ TEST_F(FlightSQLODBCMockTestBase, TestSQLColAttributeTypeName) { this->CreateTableAllDataType(); std::wstring wsql = L"SELECT * from AllTypesTable;"; - // Mock server doesn't return data source-dependent data type name - checkSQLColAttributeString(this->stmt, wsql, 1, SQL_DESC_TYPE_NAME, std::wstring(L"")); + checkSQLColAttributeString(this->stmt, wsql, 1, SQL_DESC_TYPE_NAME, + std::wstring(L"BIGINT")); + checkSQLColAttributeString(this->stmt, L"", 2, SQL_DESC_TYPE_NAME, + std::wstring(L"WVARCHAR")); + checkSQLColAttributeString(this->stmt, L"", 3, SQL_DESC_TYPE_NAME, + std::wstring(L"BINARY")); + checkSQLColAttributeString(this->stmt, L"", 4, SQL_DESC_TYPE_NAME, + std::wstring(L"DOUBLE")); this->disconnect(); } @@ -2259,6 +2273,22 @@ TEST_F(FlightSQLODBCRemoteTestBase, TestSQLColAttributeTypeName) { std::wstring wsql = L"SELECT * from $scratch.ODBCTest;"; checkSQLColAttributeString(this->stmt, wsql, 1, SQL_DESC_TYPE_NAME, std::wstring(L"INTEGER")); + checkSQLColAttributeString(this->stmt, L"", 2, SQL_DESC_TYPE_NAME, + std::wstring(L"BIGINT")); + checkSQLColAttributeString(this->stmt, L"", 3, SQL_DESC_TYPE_NAME, + std::wstring(L"DECIMAL")); + checkSQLColAttributeString(this->stmt, L"", 4, SQL_DESC_TYPE_NAME, + std::wstring(L"FLOAT")); + checkSQLColAttributeString(this->stmt, L"", 5, SQL_DESC_TYPE_NAME, + std::wstring(L"DOUBLE")); + checkSQLColAttributeString(this->stmt, L"", 6, SQL_DESC_TYPE_NAME, + std::wstring(L"BOOLEAN")); + checkSQLColAttributeString(this->stmt, L"", 7, SQL_DESC_TYPE_NAME, + std::wstring(L"DATE")); + checkSQLColAttributeString(this->stmt, L"", 8, SQL_DESC_TYPE_NAME, + std::wstring(L"TIME")); + checkSQLColAttributeString(this->stmt, L"", 9, SQL_DESC_TYPE_NAME, + std::wstring(L"TIMESTAMP")); this->disconnect(); } @@ -2271,7 +2301,13 @@ TEST_F(FlightSQLODBCMockTestBase, TestSQLColAttributesTypeName) { std::wstring wsql = L"SELECT * from AllTypesTable;"; // Mock server doesn't return data source-dependent data type name checkSQLColAttributesString(this->stmt, wsql, 1, SQL_COLUMN_TYPE_NAME, - std::wstring(L"")); + std::wstring(L"BIGINT")); + checkSQLColAttributesString(this->stmt, L"", 2, SQL_COLUMN_TYPE_NAME, + std::wstring(L"WVARCHAR")); + checkSQLColAttributesString(this->stmt, L"", 3, SQL_COLUMN_TYPE_NAME, + std::wstring(L"BINARY")); + checkSQLColAttributesString(this->stmt, L"", 4, SQL_COLUMN_TYPE_NAME, + std::wstring(L"DOUBLE")); this->disconnect(); } @@ -2283,6 +2319,22 @@ TEST_F(FlightSQLODBCRemoteTestBase, TestSQLColAttributesTypeName) { std::wstring wsql = L"SELECT * from $scratch.ODBCTest;"; checkSQLColAttributesString(this->stmt, wsql, 1, SQL_COLUMN_TYPE_NAME, std::wstring(L"INTEGER")); + checkSQLColAttributesString(this->stmt, L"", 2, SQL_COLUMN_TYPE_NAME, + std::wstring(L"BIGINT")); + checkSQLColAttributesString(this->stmt, L"", 3, SQL_COLUMN_TYPE_NAME, + std::wstring(L"DECIMAL")); + checkSQLColAttributesString(this->stmt, L"", 4, SQL_COLUMN_TYPE_NAME, + std::wstring(L"FLOAT")); + checkSQLColAttributesString(this->stmt, L"", 5, SQL_COLUMN_TYPE_NAME, + std::wstring(L"DOUBLE")); + checkSQLColAttributesString(this->stmt, L"", 6, SQL_COLUMN_TYPE_NAME, + std::wstring(L"BOOLEAN")); + checkSQLColAttributesString(this->stmt, L"", 7, SQL_COLUMN_TYPE_NAME, + std::wstring(L"DATE")); + checkSQLColAttributesString(this->stmt, L"", 8, SQL_COLUMN_TYPE_NAME, + std::wstring(L"TIME")); + checkSQLColAttributesString(this->stmt, L"", 9, SQL_COLUMN_TYPE_NAME, + std::wstring(L"TIMESTAMP")); this->disconnect(); }