Skip to content

Commit e2a3362

Browse files
alinaliBQjusting-bq
andcommitted
Extract SQLColAttribute implementation
Co-Authored-By: justing-bq <[email protected]> Co-Authored-By: alinalibq <[email protected]>
1 parent 398fc5a commit e2a3362

File tree

8 files changed

+1365
-30
lines changed

8 files changed

+1365
-30
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
@@ -1088,8 +1088,90 @@ SQLRETURN SQLColAttribute(SQLHSTMT stmt, SQLUSMALLINT record_number,
10881088
<< ", output_length: " << static_cast<const void*>(output_length)
10891089
<< ", numeric_attribute_ptr: "
10901090
<< static_cast<const void*>(numeric_attribute_ptr);
1091-
// GH-47721 TODO: Implement SQLColAttribute, pre-requisite requires SQLColumns
1092-
return SQL_INVALID_HANDLE;
1091+
1092+
using ODBC::ODBCDescriptor;
1093+
using ODBC::ODBCStatement;
1094+
return ODBCStatement::ExecuteWithDiagnostics(stmt, SQL_ERROR, [=]() {
1095+
ODBCStatement* statement = reinterpret_cast<ODBCStatement*>(stmt);
1096+
ODBCDescriptor* ird = statement->GetIRD();
1097+
SQLINTEGER output_length_int;
1098+
switch (field_identifier) {
1099+
// Numeric attributes
1100+
// internal is SQLLEN, no conversion is needed
1101+
case SQL_DESC_DISPLAY_SIZE:
1102+
case SQL_DESC_OCTET_LENGTH: {
1103+
ird->GetField(record_number, field_identifier, numeric_attribute_ptr,
1104+
buffer_length, &output_length_int);
1105+
break;
1106+
}
1107+
// internal is SQLULEN, conversion is needed.
1108+
case SQL_COLUMN_LENGTH: // ODBC 2.0
1109+
case SQL_DESC_LENGTH: {
1110+
SQLULEN temp;
1111+
ird->GetField(record_number, field_identifier, &temp, buffer_length,
1112+
&output_length_int);
1113+
if (numeric_attribute_ptr) {
1114+
*numeric_attribute_ptr = static_cast<SQLLEN>(temp);
1115+
}
1116+
break;
1117+
}
1118+
// internal is SQLINTEGER, conversion is needed.
1119+
case SQL_DESC_AUTO_UNIQUE_VALUE:
1120+
case SQL_DESC_CASE_SENSITIVE:
1121+
case SQL_DESC_NUM_PREC_RADIX: {
1122+
SQLINTEGER temp;
1123+
ird->GetField(record_number, field_identifier, &temp, buffer_length,
1124+
&output_length_int);
1125+
if (numeric_attribute_ptr) {
1126+
*numeric_attribute_ptr = static_cast<SQLLEN>(temp);
1127+
}
1128+
break;
1129+
}
1130+
// internal is SQLSMALLINT, conversion is needed.
1131+
case SQL_DESC_CONCISE_TYPE:
1132+
case SQL_DESC_COUNT:
1133+
case SQL_DESC_FIXED_PREC_SCALE:
1134+
case SQL_DESC_TYPE:
1135+
case SQL_DESC_NULLABLE:
1136+
case SQL_COLUMN_PRECISION: // ODBC 2.0
1137+
case SQL_DESC_PRECISION:
1138+
case SQL_COLUMN_SCALE: // ODBC 2.0
1139+
case SQL_DESC_SCALE:
1140+
case SQL_DESC_SEARCHABLE:
1141+
case SQL_DESC_UNNAMED:
1142+
case SQL_DESC_UNSIGNED:
1143+
case SQL_DESC_UPDATABLE: {
1144+
SQLSMALLINT temp;
1145+
ird->GetField(record_number, field_identifier, &temp, buffer_length,
1146+
&output_length_int);
1147+
if (numeric_attribute_ptr) {
1148+
*numeric_attribute_ptr = static_cast<SQLLEN>(temp);
1149+
}
1150+
break;
1151+
}
1152+
// Character attributes
1153+
case SQL_DESC_BASE_COLUMN_NAME:
1154+
case SQL_DESC_BASE_TABLE_NAME:
1155+
case SQL_DESC_CATALOG_NAME:
1156+
case SQL_DESC_LABEL:
1157+
case SQL_DESC_LITERAL_PREFIX:
1158+
case SQL_DESC_LITERAL_SUFFIX:
1159+
case SQL_DESC_LOCAL_TYPE_NAME:
1160+
case SQL_DESC_NAME:
1161+
case SQL_DESC_SCHEMA_NAME:
1162+
case SQL_DESC_TABLE_NAME:
1163+
case SQL_DESC_TYPE_NAME:
1164+
ird->GetField(record_number, field_identifier, character_attribute_ptr,
1165+
buffer_length, &output_length_int);
1166+
break;
1167+
default:
1168+
throw DriverException("Invalid descriptor field", "HY091");
1169+
}
1170+
if (output_length) {
1171+
*output_length = static_cast<SQLSMALLINT>(output_length_int);
1172+
}
1173+
return SQL_SUCCESS;
1174+
});
10931175
}
10941176

10951177
SQLRETURN SQLGetTypeInfo(SQLHSTMT stmt, SQLSMALLINT data_type) {

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

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
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/type_traits.h"
24+
#include "arrow/util/key_value_metadata.h"
2325

2426
#include <utility>
2527
#include "arrow/flight/sql/odbc/odbc_impl/exceptions.h"
@@ -40,12 +42,8 @@ constexpr int32_t DefaultDecimalPrecision = 38;
4042
constexpr int32_t DefaultLengthForVariableLengthColumns = 1024;
4143

4244
namespace {
43-
std::shared_ptr<const KeyValueMetadata> empty_metadata_map(new KeyValueMetadata);
44-
4545
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);
46+
ColumnMetadata metadata(field->metadata());
4947
return metadata;
5048
}
5149

@@ -207,10 +205,14 @@ size_t FlightSqlResultSetMetadata::GetOctetLength(int column_position) {
207205
.value_or(DefaultLengthForVariableLengthColumns);
208206
}
209207

210-
std::string FlightSqlResultSetMetadata::GetTypeName(int column_position) {
208+
std::string FlightSqlResultSetMetadata::GetTypeName(int column_position,
209+
int16_t data_type) {
211210
ColumnMetadata metadata = GetMetadata(schema_->field(column_position - 1));
212211

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

216218
Updatability FlightSqlResultSetMetadata::GetUpdatable(int column_position) {
@@ -240,19 +242,11 @@ Searchability FlightSqlResultSetMetadata::IsSearchable(int column_position) {
240242
bool FlightSqlResultSetMetadata::IsUnsigned(int column_position) {
241243
const std::shared_ptr<Field>& field = schema_->field(column_position - 1);
242244

243-
switch (field->type()->id()) {
244-
case Type::UINT8:
245-
case Type::UINT16:
246-
case Type::UINT32:
247-
case Type::UINT64:
248-
return true;
249-
default:
250-
return false;
251-
}
245+
return arrow::is_unsigned_integer(field->type()->id());
252246
}
253247

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

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, int16_t 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 Return true if the column is unsigned or 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, int16_t 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)