Skip to content

Commit 44deffe

Browse files
alinaliBQjusting-bq
andcommitted
Extract SQLColAttribute implementation
Co-Authored-By: justing-bq <[email protected]> Co-Authored-By: alinalibq <[email protected]>
1 parent 42f27ab commit 44deffe

File tree

7 files changed

+1350
-19
lines changed

7 files changed

+1350
-19
lines changed

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

Lines changed: 84 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -951,8 +951,90 @@ SQLRETURN SQLColAttribute(SQLHSTMT stmt, SQLUSMALLINT record_number,
951951
<< ", output_length: " << static_cast<const void*>(output_length)
952952
<< ", numeric_attribute_ptr: "
953953
<< static_cast<const void*>(numeric_attribute_ptr);
954-
// GH-47721 TODO: Implement SQLColAttribute, pre-requisite requires SQLColumns
955-
return SQL_INVALID_HANDLE;
954+
955+
using ODBC::ODBCDescriptor;
956+
using ODBC::ODBCStatement;
957+
return ODBCStatement::ExecuteWithDiagnostics(stmt, SQL_ERROR, [=]() {
958+
ODBCStatement* statement = reinterpret_cast<ODBCStatement*>(stmt);
959+
ODBCDescriptor* ird = statement->GetIRD();
960+
SQLINTEGER output_length_int;
961+
switch (field_identifier) {
962+
// Numeric attributes
963+
// internal is SQLLEN, no conversion is needed
964+
case SQL_DESC_DISPLAY_SIZE:
965+
case SQL_DESC_OCTET_LENGTH: {
966+
ird->GetField(record_number, field_identifier, numeric_attribute_ptr,
967+
buffer_length, &output_length_int);
968+
break;
969+
}
970+
// internal is SQLULEN, conversion is needed.
971+
case SQL_COLUMN_LENGTH: // ODBC 2.0
972+
case SQL_DESC_LENGTH: {
973+
SQLULEN temp;
974+
ird->GetField(record_number, field_identifier, &temp, buffer_length,
975+
&output_length_int);
976+
if (numeric_attribute_ptr) {
977+
*numeric_attribute_ptr = static_cast<SQLLEN>(temp);
978+
}
979+
break;
980+
}
981+
// internal is SQLINTEGER, conversion is needed.
982+
case SQL_DESC_AUTO_UNIQUE_VALUE:
983+
case SQL_DESC_CASE_SENSITIVE:
984+
case SQL_DESC_NUM_PREC_RADIX: {
985+
SQLINTEGER temp;
986+
ird->GetField(record_number, field_identifier, &temp, buffer_length,
987+
&output_length_int);
988+
if (numeric_attribute_ptr) {
989+
*numeric_attribute_ptr = static_cast<SQLLEN>(temp);
990+
}
991+
break;
992+
}
993+
// internal is SQLSMALLINT, conversion is needed.
994+
case SQL_DESC_CONCISE_TYPE:
995+
case SQL_DESC_COUNT:
996+
case SQL_DESC_FIXED_PREC_SCALE:
997+
case SQL_DESC_TYPE:
998+
case SQL_DESC_NULLABLE:
999+
case SQL_COLUMN_PRECISION: // ODBC 2.0
1000+
case SQL_DESC_PRECISION:
1001+
case SQL_COLUMN_SCALE: // ODBC 2.0
1002+
case SQL_DESC_SCALE:
1003+
case SQL_DESC_SEARCHABLE:
1004+
case SQL_DESC_UNNAMED:
1005+
case SQL_DESC_UNSIGNED:
1006+
case SQL_DESC_UPDATABLE: {
1007+
SQLSMALLINT temp;
1008+
ird->GetField(record_number, field_identifier, &temp, buffer_length,
1009+
&output_length_int);
1010+
if (numeric_attribute_ptr) {
1011+
*numeric_attribute_ptr = static_cast<SQLLEN>(temp);
1012+
}
1013+
break;
1014+
}
1015+
// Character attributes
1016+
case SQL_DESC_BASE_COLUMN_NAME:
1017+
case SQL_DESC_BASE_TABLE_NAME:
1018+
case SQL_DESC_CATALOG_NAME:
1019+
case SQL_DESC_LABEL:
1020+
case SQL_DESC_LITERAL_PREFIX:
1021+
case SQL_DESC_LITERAL_SUFFIX:
1022+
case SQL_DESC_LOCAL_TYPE_NAME:
1023+
case SQL_DESC_NAME:
1024+
case SQL_DESC_SCHEMA_NAME:
1025+
case SQL_DESC_TABLE_NAME:
1026+
case SQL_DESC_TYPE_NAME:
1027+
ird->GetField(record_number, field_identifier, character_attribute_ptr,
1028+
buffer_length, &output_length_int);
1029+
break;
1030+
default:
1031+
throw DriverException("Invalid descriptor field", "HY091");
1032+
}
1033+
if (output_length) {
1034+
*output_length = static_cast<SQLSMALLINT>(output_length_int);
1035+
}
1036+
return SQL_SUCCESS;
1037+
});
9561038
}
9571039

9581040
SQLRETURN SQLGetTypeInfo(SQLHSTMT stmt, SQLSMALLINT data_type) {

cpp/src/arrow/flight/sql/odbc/odbc_impl/flight_sql_result_set_metadata.cc

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "arrow/flight/sql/column_metadata.h"
2121
#include "arrow/flight/sql/odbc/odbc_impl/platform.h"
2222
#include "arrow/flight/sql/odbc/odbc_impl/util.h"
23+
#include "arrow/util/key_value_metadata.h"
2324

2425
#include <utility>
2526
#include "arrow/flight/sql/odbc/odbc_impl/exceptions.h"
@@ -40,12 +41,8 @@ constexpr int32_t DefaultDecimalPrecision = 38;
4041
constexpr int32_t DefaultLengthForVariableLengthColumns = 1024;
4142

4243
namespace {
43-
std::shared_ptr<const KeyValueMetadata> empty_metadata_map(new KeyValueMetadata);
44-
4544
inline ColumnMetadata GetMetadata(const std::shared_ptr<Field>& field) {
46-
const auto& metadata_map = field->metadata();
47-
48-
ColumnMetadata metadata(metadata_map ? metadata_map : empty_metadata_map);
45+
ColumnMetadata metadata(field->metadata());
4946
return metadata;
5047
}
5148

@@ -207,10 +204,13 @@ size_t FlightSqlResultSetMetadata::GetOctetLength(int column_position) {
207204
.value_or(DefaultLengthForVariableLengthColumns);
208205
}
209206

210-
std::string FlightSqlResultSetMetadata::GetTypeName(int column_position) {
207+
std::string FlightSqlResultSetMetadata::GetTypeName(int column_position, int data_type) {
211208
ColumnMetadata metadata = GetMetadata(schema_->field(column_position - 1));
212209

213-
return metadata.GetTypeName().ValueOrElse([] { return ""; });
210+
return metadata.GetTypeName().ValueOrElse([data_type] {
211+
// If we get an empty type name, figure out the type name from the data_type.
212+
return util::GetTypeNameFromSqlDataType(data_type);
213+
});
214214
}
215215

216216
Updatability FlightSqlResultSetMetadata::GetUpdatable(int column_position) {
@@ -241,18 +241,29 @@ bool FlightSqlResultSetMetadata::IsUnsigned(int column_position) {
241241
const std::shared_ptr<Field>& field = schema_->field(column_position - 1);
242242

243243
switch (field->type()->id()) {
244+
case Type::INT8:
245+
case Type::INT16:
246+
case Type::INT32:
247+
case Type::INT64:
248+
case Type::DOUBLE:
249+
case Type::FLOAT:
250+
case Type::HALF_FLOAT:
251+
case Type::DECIMAL32:
252+
case Type::DECIMAL64:
253+
case Type::DECIMAL128:
254+
case Type::DECIMAL256:
255+
return false;
244256
case Type::UINT8:
245257
case Type::UINT16:
246258
case Type::UINT32:
247259
case Type::UINT64:
248-
return true;
249260
default:
250-
return false;
261+
return true;
251262
}
252263
}
253264

254265
bool FlightSqlResultSetMetadata::IsFixedPrecScale(int column_position) {
255-
// TODO: Flight SQL column metadata does not have this, should we add to the spec?
266+
// Precision for Arrow data types are modifiable by the user
256267
return false;
257268
}
258269

cpp/src/arrow/flight/sql/odbc/odbc_impl/flight_sql_result_set_metadata.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ class FlightSqlResultSetMetadata : public ResultSetMetadata {
7777

7878
size_t GetOctetLength(int column_position) override;
7979

80-
std::string GetTypeName(int column_position) override;
80+
std::string GetTypeName(int column_position, int data_type) override;
8181

8282
Updatability GetUpdatable(int column_position) override;
8383

@@ -87,6 +87,7 @@ class FlightSqlResultSetMetadata : public ResultSetMetadata {
8787

8888
Searchability IsSearchable(int column_position) override;
8989

90+
/// \brief Returns true if the column is unsigned (not numeric)
9091
bool IsUnsigned(int column_position) override;
9192

9293
bool IsFixedPrecScale(int column_position) override;

cpp/src/arrow/flight/sql/odbc/odbc_impl/odbc_descriptor.cc

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,8 @@ void ODBCDescriptor::PopulateFromResultSetMetadata(ResultSetMetadata* rsmd) {
479479

480480
for (size_t i = 0; i < records_.size(); ++i) {
481481
size_t one_based_index = i + 1;
482+
int16_t concise_type = rsmd->GetConciseType(one_based_index);
483+
482484
records_[i].base_column_name = rsmd->GetBaseColumnName(one_based_index);
483485
records_[i].base_table_name = rsmd->GetBaseTableName(one_based_index);
484486
records_[i].catalog_name = rsmd->GetCatalogName(one_based_index);
@@ -489,9 +491,8 @@ void ODBCDescriptor::PopulateFromResultSetMetadata(ResultSetMetadata* rsmd) {
489491
records_[i].name = rsmd->GetName(one_based_index);
490492
records_[i].schema_name = rsmd->GetSchemaName(one_based_index);
491493
records_[i].table_name = rsmd->GetTableName(one_based_index);
492-
records_[i].type_name = rsmd->GetTypeName(one_based_index);
493-
records_[i].concise_type = GetSqlTypeForODBCVersion(
494-
rsmd->GetConciseType(one_based_index), is_2x_connection_);
494+
records_[i].type_name = rsmd->GetTypeName(one_based_index, concise_type);
495+
records_[i].concise_type = GetSqlTypeForODBCVersion(concise_type, is_2x_connection_);
495496
records_[i].data_ptr = nullptr;
496497
records_[i].indicator_ptr = nullptr;
497498
records_[i].display_size = rsmd->GetColumnDisplaySize(one_based_index);

cpp/src/arrow/flight/sql/odbc/odbc_impl/spi/result_set_metadata.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,8 @@
1717

1818
#pragma once
1919

20-
#include "arrow/flight/sql/odbc/odbc_impl/types.h"
21-
2220
#include <string>
21+
#include "arrow/flight/sql/odbc/odbc_impl/types.h"
2322

2423
namespace arrow::flight::sql::odbc {
2524

@@ -143,8 +142,9 @@ class ResultSetMetadata {
143142

144143
/// \brief It returns the data type as a string.
145144
/// \param column_position [in] the position of the column, starting from 1.
145+
/// \param data_type [in] the data type of the column.
146146
/// \return the data type string.
147-
virtual std::string GetTypeName(int column_position) = 0;
147+
virtual std::string GetTypeName(int column_position, int data_type) = 0;
148148

149149
/// \brief It returns a numeric values indicate the updatability of the
150150
/// column.

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ add_arrow_test(flight_sql_odbc_test
3434
SOURCES
3535
odbc_test_suite.cc
3636
odbc_test_suite.h
37+
columns_test.cc
3738
connection_test.cc
3839
# Enable Protobuf cleanup after test execution
3940
# GH-46889: move protobuf_test_util to a more common location

0 commit comments

Comments
 (0)