Skip to content

Commit 2571c2c

Browse files
authored
apacheGH-47709: [C++][FlightRPC] Return ODBC and data source information (apache#47762)
### Rationale for this change ODBC needs to give BI tools information about the driver itself and the data source it is connected to. ### What changes are included in this PR? - Implementation of `SQLGetinfo` to return driver and data source information - Add default values for SQLGetInfo in `get_info_cache.cc` - Tests ### Are these changes tested? Tested on local MSVC Windows ### Are there any user-facing changes? No * GitHub Issue: apache#47709
1 parent 6fed4f3 commit 2571c2c

File tree

6 files changed

+1321
-77
lines changed

6 files changed

+1321
-77
lines changed

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

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -942,7 +942,6 @@ SQLRETURN SQLGetInfo(SQLHDBC conn, SQLUSMALLINT info_type, SQLPOINTER info_value
942942
<< ", string_length_ptr: "
943943
<< static_cast<const void*>(string_length_ptr);
944944

945-
// GH-47709 TODO: Update SQLGetInfo implementation and add tests for SQLGetInfo
946945
using ODBC::ODBCConnection;
947946

948947
return ODBCConnection::ExecuteWithDiagnostics(conn, SQL_ERROR, [=]() {
@@ -955,9 +954,8 @@ SQLRETURN SQLGetInfo(SQLHDBC conn, SQLUSMALLINT info_type, SQLPOINTER info_value
955954
return static_cast<SQLRETURN>(SQL_ERROR);
956955
}
957956

958-
connection->GetInfo(info_type, info_value_ptr, buf_len, string_length_ptr,
959-
is_unicode);
960-
return static_cast<SQLRETURN>(SQL_SUCCESS);
957+
return connection->GetInfo(info_type, info_value_ptr, buf_len, string_length_ptr,
958+
is_unicode);
961959
});
962960
}
963961

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

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -918,21 +918,21 @@ bool GetInfoCache::LoadInfoFromServer() {
918918
break;
919919
}
920920
case SqlInfoOptions::SQL_SUPPORTED_RESULT_SET_TYPES:
921-
// Ignored. Warpdrive supports forward-only only.
921+
// Ignored. Arrow ODBC supports forward-only only.
922922
break;
923923
case SqlInfoOptions::SQL_SUPPORTED_CONCURRENCIES_FOR_RESULT_SET_UNSPECIFIED:
924-
// Ignored. Warpdrive supports forward-only only.
924+
// Ignored. Arrow ODBC supports forward-only only.
925925
break;
926926
case SqlInfoOptions::SQL_SUPPORTED_CONCURRENCIES_FOR_RESULT_SET_FORWARD_ONLY:
927-
// Ignored. Warpdrive supports forward-only only.
927+
// Ignored. Arrow ODBC supports forward-only only.
928928
break;
929929
case SqlInfoOptions::
930930
SQL_SUPPORTED_CONCURRENCIES_FOR_RESULT_SET_SCROLL_SENSITIVE:
931-
// Ignored. Warpdrive supports forward-only only.
931+
// Ignored. Arrow ODBC supports forward-only only.
932932
break;
933933
case SqlInfoOptions::
934934
SQL_SUPPORTED_CONCURRENCIES_FOR_RESULT_SET_SCROLL_INSENSITIVE:
935-
// Ignored. Warpdrive supports forward-only only.
935+
// Ignored. Arrow ODBC supports forward-only only.
936936
break;
937937

938938
// List<string> properties
@@ -1132,6 +1132,7 @@ void GetInfoCache::LoadDefaultsForMissingEntries() {
11321132
SetDefaultIfMissing(info_, SQL_CONVERT_DECIMAL, static_cast<uint32_t>(0));
11331133
SetDefaultIfMissing(info_, SQL_CONVERT_DOUBLE, static_cast<uint32_t>(0));
11341134
SetDefaultIfMissing(info_, SQL_CONVERT_FLOAT, static_cast<uint32_t>(0));
1135+
SetDefaultIfMissing(info_, SQL_CONVERT_FUNCTIONS, static_cast<uint32_t>(0));
11351136
SetDefaultIfMissing(info_, SQL_CONVERT_GUID, static_cast<uint32_t>(0));
11361137
SetDefaultIfMissing(info_, SQL_CONVERT_INTEGER, static_cast<uint32_t>(0));
11371138
SetDefaultIfMissing(info_, SQL_CONVERT_INTERVAL_YEAR_MONTH, static_cast<uint32_t>(0));
@@ -1210,6 +1211,7 @@ void GetInfoCache::LoadDefaultsForMissingEntries() {
12101211
SetDefaultIfMissing(info_, SQL_MAX_COLUMNS_IN_ORDER_BY, static_cast<uint16_t>(0));
12111212
SetDefaultIfMissing(info_, SQL_MAX_COLUMNS_IN_SELECT, static_cast<uint16_t>(0));
12121213
SetDefaultIfMissing(info_, SQL_MAX_COLUMNS_IN_TABLE, static_cast<uint16_t>(0));
1214+
SetDefaultIfMissing(info_, SQL_MAX_CONCURRENT_ACTIVITIES, static_cast<uint16_t>(0));
12131215
SetDefaultIfMissing(info_, SQL_MAX_CURSOR_NAME_LEN, static_cast<uint16_t>(0));
12141216
SetDefaultIfMissing(info_, SQL_MAX_DRIVER_CONNECTIONS, static_cast<uint16_t>(0));
12151217
SetDefaultIfMissing(info_, SQL_MAX_IDENTIFIER_LEN, static_cast<uint16_t>(65535));
@@ -1229,6 +1231,7 @@ void GetInfoCache::LoadDefaultsForMissingEntries() {
12291231
SetDefaultIfMissing(info_, SQL_OJ_CAPABILITIES,
12301232
static_cast<uint32_t>(SQL_OJ_LEFT | SQL_OJ_RIGHT | SQL_OJ_FULL));
12311233
SetDefaultIfMissing(info_, SQL_ORDER_BY_COLUMNS_IN_SELECT, "Y");
1234+
SetDefaultIfMissing(info_, SQL_OUTER_JOINS, "N");
12321235
SetDefaultIfMissing(info_, SQL_PROCEDURE_TERM, "");
12331236
SetDefaultIfMissing(info_, SQL_PROCEDURES, "N");
12341237
SetDefaultIfMissing(info_, SQL_QUOTED_IDENTIFIER_CASE,
@@ -1237,6 +1240,7 @@ void GetInfoCache::LoadDefaultsForMissingEntries() {
12371240
SetDefaultIfMissing(info_, SQL_SCHEMA_USAGE,
12381241
static_cast<uint32_t>(SQL_SU_DML_STATEMENTS));
12391242
SetDefaultIfMissing(info_, SQL_SEARCH_PATTERN_ESCAPE, "\\");
1243+
SetDefaultIfMissing(info_, SQL_SPECIAL_CHARACTERS, "");
12401244
SetDefaultIfMissing(
12411245
info_, SQL_SERVER_NAME,
12421246
"Arrow Flight SQL Server"); // This might actually need to be the hostname.
@@ -1291,6 +1295,16 @@ void GetInfoCache::LoadDefaultsForMissingEntries() {
12911295
SQL_FN_TSI_FRAC_SECOND | SQL_FN_TSI_SECOND | SQL_FN_TSI_MINUTE |
12921296
SQL_FN_TSI_HOUR | SQL_FN_TSI_DAY | SQL_FN_TSI_WEEK |
12931297
SQL_FN_TSI_MONTH | SQL_FN_TSI_QUARTER | SQL_FN_TSI_YEAR));
1298+
SetDefaultIfMissing(
1299+
info_, SQL_TIMEDATE_FUNCTIONS,
1300+
static_cast<uint32_t>(
1301+
SQL_FN_TD_CURRENT_DATE | SQL_FN_TD_CURRENT_TIME | SQL_FN_TD_CURRENT_TIMESTAMP |
1302+
SQL_FN_TD_CURDATE | SQL_FN_TD_CURTIME | SQL_FN_TD_DAYNAME |
1303+
SQL_FN_TD_DAYOFMONTH | SQL_FN_TD_DAYOFWEEK | SQL_FN_TD_DAYOFYEAR |
1304+
SQL_FN_TD_EXTRACT | SQL_FN_TD_HOUR | SQL_FN_TD_MINUTE | SQL_FN_TD_MONTH |
1305+
SQL_FN_TD_MONTHNAME | SQL_FN_TD_NOW | SQL_FN_TD_QUARTER | SQL_FN_TD_SECOND |
1306+
SQL_FN_TD_TIMESTAMPADD | SQL_FN_TD_TIMESTAMPDIFF | SQL_FN_TD_WEEK |
1307+
SQL_FN_TD_YEAR));
12941308
SetDefaultIfMissing(info_, SQL_UNION,
12951309
static_cast<uint32_t>(SQL_U_UNION | SQL_U_UNION_ALL));
12961310
SetDefaultIfMissing(info_, SQL_XOPEN_CLI_YEAR, "1995");

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

Lines changed: 59 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -88,152 +88,144 @@ void ODBCConnection::Connect(std::string dsn,
8888
attribute_tracking_statement_ = std::make_shared<ODBCStatement>(*this, spi_statement);
8989
}
9090

91-
void ODBCConnection::GetInfo(SQLUSMALLINT info_type, SQLPOINTER value,
92-
SQLSMALLINT buffer_length, SQLSMALLINT* output_length,
93-
bool is_unicode) {
91+
SQLRETURN ODBCConnection::GetInfo(SQLUSMALLINT info_type, SQLPOINTER value,
92+
SQLSMALLINT buffer_length, SQLSMALLINT* output_length,
93+
bool is_unicode) {
9494
switch (info_type) {
9595
case SQL_ACTIVE_ENVIRONMENTS:
9696
GetAttribute(static_cast<SQLUSMALLINT>(0), value, buffer_length, output_length);
97-
break;
97+
return SQL_SUCCESS;
9898
#ifdef SQL_ASYNC_DBC_FUNCTIONS
9999
case SQL_ASYNC_DBC_FUNCTIONS:
100100
GetAttribute(static_cast<SQLUINTEGER>(SQL_ASYNC_DBC_NOT_CAPABLE), value,
101101
buffer_length, output_length);
102-
break;
102+
return SQL_SUCCESS;
103103
#endif
104104
case SQL_ASYNC_MODE:
105105
GetAttribute(static_cast<SQLUINTEGER>(SQL_AM_NONE), value, buffer_length,
106106
output_length);
107-
break;
107+
return SQL_SUCCESS;
108108
#ifdef SQL_ASYNC_NOTIFICATION
109109
case SQL_ASYNC_NOTIFICATION:
110110
GetAttribute(static_cast<SQLUINTEGER>(SQL_ASYNC_NOTIFICATION_NOT_CAPABLE), value,
111111
buffer_length, output_length);
112-
break;
112+
return SQL_SUCCESS;
113113
#endif
114114
case SQL_BATCH_ROW_COUNT:
115115
GetAttribute(static_cast<SQLUINTEGER>(0), value, buffer_length, output_length);
116-
break;
116+
return SQL_SUCCESS;
117117
case SQL_BATCH_SUPPORT:
118118
GetAttribute(static_cast<SQLUINTEGER>(0), value, buffer_length, output_length);
119-
break;
119+
return SQL_SUCCESS;
120120
case SQL_DATA_SOURCE_NAME:
121-
GetStringAttribute(is_unicode, dsn_, true, value, buffer_length, output_length,
122-
GetDiagnostics());
123-
break;
121+
return GetStringAttribute(is_unicode, dsn_, true, value, buffer_length,
122+
output_length, GetDiagnostics());
124123
case SQL_DRIVER_ODBC_VER:
125-
GetStringAttribute(is_unicode, "03.80", true, value, buffer_length, output_length,
126-
GetDiagnostics());
127-
break;
124+
return GetStringAttribute(is_unicode, "03.80", true, value, buffer_length,
125+
output_length, GetDiagnostics());
128126
case SQL_DYNAMIC_CURSOR_ATTRIBUTES1:
129127
GetAttribute(static_cast<SQLUINTEGER>(0), value, buffer_length, output_length);
130-
break;
128+
return SQL_SUCCESS;
131129
case SQL_DYNAMIC_CURSOR_ATTRIBUTES2:
132130
GetAttribute(static_cast<SQLUINTEGER>(0), value, buffer_length, output_length);
133-
break;
131+
return SQL_SUCCESS;
134132
case SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES1:
135133
GetAttribute(static_cast<SQLUINTEGER>(SQL_CA1_NEXT), value, buffer_length,
136134
output_length);
137-
break;
135+
return SQL_SUCCESS;
138136
case SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2:
139137
GetAttribute(static_cast<SQLUINTEGER>(SQL_CA2_READ_ONLY_CONCURRENCY), value,
140138
buffer_length, output_length);
141-
break;
139+
return SQL_SUCCESS;
142140
case SQL_FILE_USAGE:
143141
GetAttribute(static_cast<SQLUSMALLINT>(SQL_FILE_NOT_SUPPORTED), value,
144142
buffer_length, output_length);
145-
break;
143+
return SQL_SUCCESS;
146144
case SQL_KEYSET_CURSOR_ATTRIBUTES1:
147145
GetAttribute(static_cast<SQLUINTEGER>(0), value, buffer_length, output_length);
148-
break;
146+
return SQL_SUCCESS;
149147
case SQL_KEYSET_CURSOR_ATTRIBUTES2:
150148
GetAttribute(static_cast<SQLUINTEGER>(0), value, buffer_length, output_length);
151-
break;
149+
return SQL_SUCCESS;
152150
case SQL_MAX_ASYNC_CONCURRENT_STATEMENTS:
153151
GetAttribute(static_cast<SQLUINTEGER>(0), value, buffer_length, output_length);
154-
break;
152+
return SQL_SUCCESS;
155153
case SQL_ODBC_INTERFACE_CONFORMANCE:
156154
GetAttribute(static_cast<SQLUINTEGER>(SQL_OIC_CORE), value, buffer_length,
157155
output_length);
158-
break;
156+
return SQL_SUCCESS;
159157
// case SQL_ODBC_STANDARD_CLI_CONFORMANCE: - mentioned in SQLGetInfo spec with no
160158
// description and there is no constant for this.
161159
case SQL_PARAM_ARRAY_ROW_COUNTS:
162160
GetAttribute(static_cast<SQLUINTEGER>(SQL_PARC_NO_BATCH), value, buffer_length,
163161
output_length);
164-
break;
162+
return SQL_SUCCESS;
165163
case SQL_PARAM_ARRAY_SELECTS:
166164
GetAttribute(static_cast<SQLUINTEGER>(SQL_PAS_NO_SELECT), value, buffer_length,
167165
output_length);
168-
break;
166+
return SQL_SUCCESS;
169167
case SQL_ROW_UPDATES:
170-
GetStringAttribute(is_unicode, "N", true, value, buffer_length, output_length,
171-
GetDiagnostics());
172-
break;
168+
return GetStringAttribute(is_unicode, "N", true, value, buffer_length,
169+
output_length, GetDiagnostics());
173170
case SQL_SCROLL_OPTIONS:
174171
GetAttribute(static_cast<SQLUINTEGER>(SQL_SO_FORWARD_ONLY), value, buffer_length,
175172
output_length);
176-
break;
173+
return SQL_SUCCESS;
177174
case SQL_STATIC_CURSOR_ATTRIBUTES1:
178175
GetAttribute(static_cast<SQLUINTEGER>(0), value, buffer_length, output_length);
179-
break;
176+
return SQL_SUCCESS;
180177
case SQL_STATIC_CURSOR_ATTRIBUTES2:
181178
GetAttribute(static_cast<SQLUINTEGER>(0), value, buffer_length, output_length);
182-
break;
179+
return SQL_SUCCESS;
183180
case SQL_BOOKMARK_PERSISTENCE:
184181
GetAttribute(static_cast<SQLUINTEGER>(0), value, buffer_length, output_length);
185-
break;
182+
return SQL_SUCCESS;
186183
case SQL_DESCRIBE_PARAMETER:
187-
GetStringAttribute(is_unicode, "N", true, value, buffer_length, output_length,
188-
GetDiagnostics());
189-
break;
184+
return GetStringAttribute(is_unicode, "N", true, value, buffer_length,
185+
output_length, GetDiagnostics());
190186
case SQL_MULT_RESULT_SETS:
191-
GetStringAttribute(is_unicode, "N", true, value, buffer_length, output_length,
192-
GetDiagnostics());
193-
break;
187+
return GetStringAttribute(is_unicode, "N", true, value, buffer_length,
188+
output_length, GetDiagnostics());
194189
case SQL_MULTIPLE_ACTIVE_TXN:
195-
GetStringAttribute(is_unicode, "N", true, value, buffer_length, output_length,
196-
GetDiagnostics());
197-
break;
190+
return GetStringAttribute(is_unicode, "N", true, value, buffer_length,
191+
output_length, GetDiagnostics());
198192
case SQL_NEED_LONG_DATA_LEN:
199-
GetStringAttribute(is_unicode, "N", true, value, buffer_length, output_length,
200-
GetDiagnostics());
201-
break;
193+
return GetStringAttribute(is_unicode, "N", true, value, buffer_length,
194+
output_length, GetDiagnostics());
202195
case SQL_TXN_CAPABLE:
203196
GetAttribute(static_cast<SQLUSMALLINT>(SQL_TC_NONE), value, buffer_length,
204197
output_length);
205-
break;
198+
return SQL_SUCCESS;
206199
case SQL_TXN_ISOLATION_OPTION:
207200
GetAttribute(static_cast<SQLUINTEGER>(0), value, buffer_length, output_length);
208-
break;
201+
return SQL_SUCCESS;
209202
case SQL_TABLE_TERM:
210-
GetStringAttribute(is_unicode, "table", true, value, buffer_length, output_length,
211-
GetDiagnostics());
212-
break;
203+
return GetStringAttribute(is_unicode, "table", true, value, buffer_length,
204+
output_length, GetDiagnostics());
213205
// Deprecated ODBC 2.x fields required for backwards compatibility.
214206
case SQL_ODBC_API_CONFORMANCE:
215207
GetAttribute(static_cast<SQLUSMALLINT>(SQL_OAC_LEVEL1), value, buffer_length,
216208
output_length);
217-
break;
209+
return SQL_SUCCESS;
218210
case SQL_FETCH_DIRECTION:
219211
GetAttribute(static_cast<SQLINTEGER>(SQL_FETCH_NEXT), value, buffer_length,
220212
output_length);
221-
break;
213+
return SQL_SUCCESS;
222214
case SQL_LOCK_TYPES:
223215
GetAttribute(static_cast<SQLINTEGER>(0), value, buffer_length, output_length);
224-
break;
216+
return SQL_SUCCESS;
225217
case SQL_POS_OPERATIONS:
226218
GetAttribute(static_cast<SQLINTEGER>(0), value, buffer_length, output_length);
227-
break;
219+
return SQL_SUCCESS;
228220
case SQL_POSITIONED_STATEMENTS:
229221
GetAttribute(static_cast<SQLINTEGER>(0), value, buffer_length, output_length);
230-
break;
222+
return SQL_SUCCESS;
231223
case SQL_SCROLL_CONCURRENCY:
232224
GetAttribute(static_cast<SQLINTEGER>(0), value, buffer_length, output_length);
233-
break;
225+
return SQL_SUCCESS;
234226
case SQL_STATIC_SENSITIVITY:
235227
GetAttribute(static_cast<SQLINTEGER>(0), value, buffer_length, output_length);
236-
break;
228+
return SQL_SUCCESS;
237229

238230
// Driver-level string properties.
239231
case SQL_USER_NAME:
@@ -268,9 +260,8 @@ void ODBCConnection::GetInfo(SQLUSMALLINT info_type, SQLPOINTER value,
268260
case SQL_XOPEN_CLI_YEAR: {
269261
const auto& info = spi_connection_->GetInfo(info_type);
270262
const std::string& info_value = boost::get<std::string>(info);
271-
GetStringAttribute(is_unicode, info_value, true, value, buffer_length,
272-
output_length, GetDiagnostics());
273-
break;
263+
return GetStringAttribute(is_unicode, info_value, true, value, buffer_length,
264+
output_length, GetDiagnostics());
274265
}
275266

276267
// Driver-level 32-bit integer properties.
@@ -360,7 +351,7 @@ void ODBCConnection::GetInfo(SQLUSMALLINT info_type, SQLPOINTER value,
360351
const auto& info = spi_connection_->GetInfo(info_type);
361352
uint32_t info_value = boost::get<uint32_t>(info);
362353
GetAttribute(info_value, value, buffer_length, output_length);
363-
break;
354+
return SQL_SUCCESS;
364355
}
365356

366357
// Driver-level 16-bit integer properties.
@@ -395,7 +386,7 @@ void ODBCConnection::GetInfo(SQLUSMALLINT info_type, SQLPOINTER value,
395386
const auto& info = spi_connection_->GetInfo(info_type);
396387
uint16_t info_value = boost::get<uint16_t>(info);
397388
GetAttribute(info_value, value, buffer_length, output_length);
398-
break;
389+
return SQL_SUCCESS;
399390
}
400391

401392
// Special case - SQL_DATABASE_NAME is an alias for SQL_ATTR_CURRENT_CATALOG.
@@ -405,13 +396,15 @@ void ODBCConnection::GetInfo(SQLUSMALLINT info_type, SQLPOINTER value,
405396
throw DriverException("Optional feature not supported.", "HYC00");
406397
}
407398
const std::string& info_value = boost::get<std::string>(*attr);
408-
GetStringAttribute(is_unicode, info_value, true, value, buffer_length,
409-
output_length, GetDiagnostics());
410-
break;
399+
return GetStringAttribute(is_unicode, info_value, true, value, buffer_length,
400+
output_length, GetDiagnostics());
411401
}
412402
default:
413-
throw DriverException("Unknown SQLGetInfo type: " + std::to_string(info_type));
403+
throw DriverException("Unknown SQLGetInfo type: " + std::to_string(info_type),
404+
"HY096");
414405
}
406+
407+
return SQL_ERROR;
415408
}
416409

417410
void ODBCConnection::SetConnectAttr(SQLINTEGER attribute, SQLPOINTER value,

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@ class ODBCConnection : public ODBCHandle<ODBCConnection> {
5353
const arrow::flight::sql::odbc::Connection::ConnPropertyMap& properties,
5454
std::vector<std::string_view>& missing_properties);
5555

56-
void GetInfo(SQLUSMALLINT info_type, SQLPOINTER value, SQLSMALLINT buffer_length,
57-
SQLSMALLINT* output_length, bool is_unicode);
56+
SQLRETURN GetInfo(SQLUSMALLINT info_type, SQLPOINTER value, SQLSMALLINT buffer_length,
57+
SQLSMALLINT* output_length, bool is_unicode);
5858
void SetConnectAttr(SQLINTEGER attribute, SQLPOINTER value, SQLINTEGER string_length,
5959
bool isUnicode);
6060
SQLRETURN GetConnectAttr(SQLINTEGER attribute, SQLPOINTER value,

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ add_arrow_test(flight_sql_odbc_test
3535
odbc_test_suite.cc
3636
odbc_test_suite.h
3737
connection_attr_test.cc
38+
connection_info_test.cc
3839
connection_test.cc
3940
errors_test.cc
4041
statement_attr_test.cc

0 commit comments

Comments
 (0)