Skip to content

Commit f83c554

Browse files
authored
GH-49250: [C++][FlightRPC] ODBC: SQLError for macOS (#49251)
### Rationale for this change #49250 ### What changes are included in this PR? - Implement SQLError for macOS - Update SQLError related tests for macOS ### Are these changes tested? - SQLError Tests are tested locally on macOS ### Are there any user-facing changes? N/A * GitHub Issue: #49250 Authored-by: Alina (Xi) Li <alinal@bitquilltech.com> Signed-off-by: David Li <li.davidm96@gmail.com>
1 parent bbf337b commit f83c554

File tree

5 files changed

+137
-34
lines changed

5 files changed

+137
-34
lines changed

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,18 @@ SQLRETURN SQL_API SQLGetDiagRec(SQLSMALLINT handle_type, SQLHANDLE handle,
8383
buffer_length, text_length_ptr);
8484
}
8585

86+
#if defined(__APPLE__)
87+
// macOS ODBC Driver Manager doesn't map SQLError to SQLGetDiagRec, so we need to
88+
// implement SQLError for macOS.
89+
// on Windows, SQLError mapping implemented by Driver Manager is preferred.
90+
SQLRETURN SQL_API SQLError(SQLHENV env, SQLHDBC conn, SQLHSTMT stmt, SQLWCHAR* sql_state,
91+
SQLINTEGER* native_error_ptr, SQLWCHAR* message_text,
92+
SQLSMALLINT buffer_length, SQLSMALLINT* text_length_ptr) {
93+
return arrow::flight::sql::odbc::SQLError(env, conn, stmt, sql_state, native_error_ptr,
94+
message_text, buffer_length, text_length_ptr);
95+
}
96+
#endif // __APPLE__
97+
8698
SQLRETURN SQL_API SQLGetEnvAttr(SQLHENV env, SQLINTEGER attr, SQLPOINTER value_ptr,
8799
SQLINTEGER buffer_len, SQLINTEGER* str_len_ptr) {
88100
return arrow::flight::sql::odbc::SQLGetEnvAttr(env, attr, value_ptr, buffer_len,

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

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,56 @@ SQLRETURN SQLFreeStmt(SQLHSTMT handle, SQLUSMALLINT option) {
247247
return SQL_ERROR;
248248
}
249249

250+
#if defined(__APPLE__)
251+
SQLRETURN SQLError(SQLHENV env, SQLHDBC conn, SQLHSTMT stmt, SQLWCHAR* sql_state,
252+
SQLINTEGER* native_error_ptr, SQLWCHAR* message_text,
253+
SQLSMALLINT buffer_length, SQLSMALLINT* text_length_ptr) {
254+
ARROW_LOG(DEBUG) << "SQLError called with env: " << env << ", conn: " << conn
255+
<< ", stmt: " << stmt
256+
<< ", sql_state: " << static_cast<const void*>(sql_state)
257+
<< ", native_error_ptr: " << static_cast<const void*>(native_error_ptr)
258+
<< ", message_text: " << static_cast<const void*>(message_text)
259+
<< ", buffer_length: " << buffer_length
260+
<< ", text_length_ptr: " << static_cast<const void*>(text_length_ptr);
261+
262+
SQLSMALLINT handle_type;
263+
SQLHANDLE handle;
264+
265+
if (env) {
266+
handle_type = SQL_HANDLE_ENV;
267+
handle = static_cast<SQLHANDLE>(env);
268+
} else if (conn) {
269+
handle_type = SQL_HANDLE_DBC;
270+
handle = static_cast<SQLHANDLE>(conn);
271+
} else if (stmt) {
272+
handle_type = SQL_HANDLE_STMT;
273+
handle = static_cast<SQLHANDLE>(stmt);
274+
} else {
275+
return static_cast<SQLRETURN>(SQL_INVALID_HANDLE);
276+
}
277+
278+
// Use the last record
279+
SQLINTEGER diag_number;
280+
SQLSMALLINT diag_number_length;
281+
282+
SQLRETURN ret = arrow::flight::sql::odbc::SQLGetDiagField(
283+
handle_type, handle, 0, SQL_DIAG_NUMBER, &diag_number, sizeof(SQLINTEGER), 0);
284+
if (ret != SQL_SUCCESS) {
285+
return ret;
286+
}
287+
288+
if (diag_number == 0) {
289+
return SQL_NO_DATA;
290+
}
291+
292+
SQLSMALLINT rec_number = static_cast<SQLSMALLINT>(diag_number);
293+
294+
return arrow::flight::sql::odbc::SQLGetDiagRec(
295+
handle_type, handle, rec_number, sql_state, native_error_ptr, message_text,
296+
buffer_length, text_length_ptr);
297+
}
298+
#endif // __APPLE__
299+
250300
inline bool IsValidStringFieldArgs(SQLPOINTER diag_info_ptr, SQLSMALLINT buffer_length,
251301
SQLSMALLINT* string_length_ptr, bool is_unicode) {
252302
const SQLSMALLINT char_size = is_unicode ? GetSqlWCharSize() : sizeof(char);
@@ -736,7 +786,6 @@ SQLRETURN SQLGetConnectAttr(SQLHDBC conn, SQLINTEGER attribute, SQLPOINTER value
736786
<< ", attribute: " << attribute << ", value_ptr: " << value_ptr
737787
<< ", buffer_length: " << buffer_length << ", string_length_ptr: "
738788
<< static_cast<const void*>(string_length_ptr);
739-
740789
using ODBC::ODBCConnection;
741790

742791
return ODBCConnection::ExecuteWithDiagnostics(conn, SQL_ERROR, [=]() {

cpp/src/arrow/flight/sql/odbc/odbc_api_internal.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,12 @@ namespace arrow::flight::sql::odbc {
3131
SQLHANDLE* result);
3232
[[nodiscard]] SQLRETURN SQLFreeHandle(SQLSMALLINT type, SQLHANDLE handle);
3333
[[nodiscard]] SQLRETURN SQLFreeStmt(SQLHSTMT stmt, SQLUSMALLINT option);
34+
#if defined(__APPLE__)
35+
[[nodiscard]] SQLRETURN SQLError(SQLHENV env, SQLHDBC conn, SQLHSTMT stmt,
36+
SQLWCHAR* sql_state, SQLINTEGER* native_error_ptr,
37+
SQLWCHAR* message_text, SQLSMALLINT buffer_length,
38+
SQLSMALLINT* text_length_ptr);
39+
#endif // __APPLE__
3440
[[nodiscard]] SQLRETURN SQLGetDiagField(SQLSMALLINT handle_type, SQLHANDLE handle,
3541
SQLSMALLINT rec_number,
3642
SQLSMALLINT diag_identifier,

cpp/src/arrow/flight/sql/odbc/tests/errors_test.cc

Lines changed: 67 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ using TestTypesHandle = ::testing::Types<FlightSQLOdbcEnvConnHandleMockTestBase,
4747
FlightSQLOdbcEnvConnHandleRemoteTestBase>;
4848
TYPED_TEST_SUITE(ErrorsHandleTest, TestTypesHandle);
4949

50+
using ODBC::SqlWcharToString;
51+
5052
TYPED_TEST(ErrorsHandleTest, TestSQLGetDiagFieldWForConnectFailure) {
5153
// Invalid connect string
5254
std::string connect_str = this->GetInvalidConnectionString();
@@ -90,9 +92,12 @@ TYPED_TEST(ErrorsHandleTest, TestSQLGetDiagFieldWForConnectFailure) {
9092
SQLWCHAR message_text[kOdbcBufferSize];
9193
SQLSMALLINT message_text_length;
9294

93-
EXPECT_EQ(SQL_SUCCESS,
94-
SQLGetDiagField(SQL_HANDLE_DBC, this->conn, RECORD_1, SQL_DIAG_MESSAGE_TEXT,
95-
message_text, kOdbcBufferSize, &message_text_length));
95+
SQLRETURN ret =
96+
SQLGetDiagField(SQL_HANDLE_DBC, this->conn, RECORD_1, SQL_DIAG_MESSAGE_TEXT,
97+
message_text, kOdbcBufferSize, &message_text_length);
98+
99+
// dependent on the size of the message it could output SQL_SUCCESS_WITH_INFO
100+
EXPECT_TRUE(ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO);
96101

97102
EXPECT_GT(message_text_length, 100);
98103

@@ -114,10 +119,9 @@ TYPED_TEST(ErrorsHandleTest, TestSQLGetDiagFieldWForConnectFailure) {
114119
EXPECT_EQ(
115120
SQL_SUCCESS,
116121
SQLGetDiagField(SQL_HANDLE_DBC, this->conn, RECORD_1, SQL_DIAG_SQLSTATE, sql_state,
117-
sql_state_size * arrow::flight::sql::odbc::GetSqlWCharSize(),
118-
&sql_state_length));
122+
sql_state_size * GetSqlWCharSize(), &sql_state_length));
119123

120-
EXPECT_EQ(std::wstring(L"28000"), std::wstring(sql_state));
124+
EXPECT_EQ(kErrorState28000, SqlWcharToString(sql_state));
121125
}
122126

123127
TYPED_TEST(ErrorsHandleTest, DISABLED_TestSQLGetDiagFieldWForConnectFailureNTS) {
@@ -156,6 +160,8 @@ TYPED_TEST(ErrorsHandleTest, DISABLED_TestSQLGetDiagFieldWForConnectFailureNTS)
156160
EXPECT_GT(message_text_length, 100);
157161
}
158162

163+
// iODBC does not support application allocated descriptors.
164+
#ifndef __APPLE__
159165
TYPED_TEST(ErrorsTest, TestSQLGetDiagFieldWForDescriptorFailureFromDriverManager) {
160166
SQLHDESC descriptor;
161167

@@ -216,7 +222,7 @@ TYPED_TEST(ErrorsTest, TestSQLGetDiagFieldWForDescriptorFailureFromDriverManager
216222
SQLGetDiagField(SQL_HANDLE_DESC, descriptor, RECORD_1, SQL_DIAG_SQLSTATE, sql_state,
217223
sql_state_size * GetSqlWCharSize(), &sql_state_length));
218224

219-
EXPECT_EQ(std::wstring(L"IM001"), std::wstring(sql_state));
225+
EXPECT_EQ(kErrorStateIM001, SqlWcharToString(sql_state));
220226

221227
// Free descriptor handle
222228
EXPECT_EQ(SQL_SUCCESS, SQLFreeHandle(SQL_HANDLE_DESC, descriptor));
@@ -245,13 +251,14 @@ TYPED_TEST(ErrorsTest, TestSQLGetDiagRecForDescriptorFailureFromDriverManager) {
245251
EXPECT_EQ(0, native_error);
246252

247253
// API not implemented error from driver manager
248-
EXPECT_EQ(std::wstring(L"IM001"), std::wstring(sql_state));
254+
EXPECT_EQ(kErrorStateIM001, SqlWcharToString(sql_state));
249255

250256
EXPECT_FALSE(std::wstring(message).empty());
251257

252258
// Free descriptor handle
253259
EXPECT_EQ(SQL_SUCCESS, SQLFreeHandle(SQL_HANDLE_DESC, descriptor));
254260
}
261+
#endif // __APPLE__
255262

256263
TYPED_TEST(ErrorsHandleTest, TestSQLGetDiagRecForConnectFailure) {
257264
// Invalid connect string
@@ -282,7 +289,7 @@ TYPED_TEST(ErrorsHandleTest, TestSQLGetDiagRecForConnectFailure) {
282289

283290
EXPECT_EQ(200, native_error);
284291

285-
EXPECT_EQ(std::wstring(L"28000"), std::wstring(sql_state));
292+
EXPECT_EQ(kErrorState28000, SqlWcharToString(sql_state));
286293

287294
EXPECT_FALSE(std::wstring(message).empty());
288295
}
@@ -305,11 +312,17 @@ TYPED_TEST(ErrorsTest, TestSQLGetDiagRecInputData) {
305312
nullptr, 0, nullptr));
306313

307314
// Invalid handle
315+
#ifdef __APPLE__
316+
// MacOS ODBC driver manager requires connection handle
317+
EXPECT_EQ(SQL_INVALID_HANDLE,
318+
SQLGetDiagRec(0, this->conn, 1, nullptr, nullptr, nullptr, 0, nullptr));
319+
#else
308320
EXPECT_EQ(SQL_INVALID_HANDLE,
309321
SQLGetDiagRec(0, nullptr, 0, nullptr, nullptr, nullptr, 0, nullptr));
322+
#endif // __APPLE__
310323
}
311324

312-
TYPED_TEST(ErrorsTest, TestSQLErrorInputData) {
325+
TYPED_TEST(ErrorsOdbcV2Test, TestSQLErrorInputData) {
313326
// Test ODBC 2.0 API SQLError. Driver manager maps SQLError to SQLGetDiagRec.
314327
// SQLError does not post diagnostic records for itself.
315328

@@ -320,8 +333,13 @@ TYPED_TEST(ErrorsTest, TestSQLErrorInputData) {
320333
EXPECT_EQ(SQL_NO_DATA, SQLError(nullptr, this->conn, nullptr, nullptr, nullptr, nullptr,
321334
0, nullptr));
322335

336+
#ifdef __APPLE__
337+
EXPECT_EQ(SQL_NO_DATA, SQLError(SQL_NULL_HENV, this->conn, this->stmt, nullptr, nullptr,
338+
nullptr, 0, nullptr));
339+
#else
323340
EXPECT_EQ(SQL_NO_DATA, SQLError(nullptr, nullptr, this->stmt, nullptr, nullptr, nullptr,
324341
0, nullptr));
342+
#endif // __APPLE__
325343

326344
// Invalid handle
327345
EXPECT_EQ(SQL_INVALID_HANDLE,
@@ -345,12 +363,12 @@ TYPED_TEST(ErrorsTest, TestSQLErrorEnvErrorFromDriverManager) {
345363
ASSERT_EQ(SQL_SUCCESS, SQLError(this->env, nullptr, nullptr, sql_state, &native_error,
346364
message, SQL_MAX_MESSAGE_LENGTH, &message_length));
347365

348-
EXPECT_GT(message_length, 50);
366+
EXPECT_GT(message_length, 40);
349367

350368
EXPECT_EQ(0, native_error);
351369

352370
// Function sequence error state from driver manager
353-
EXPECT_EQ(std::wstring(L"HY010"), std::wstring(sql_state));
371+
EXPECT_EQ(kErrorStateHY010, SqlWcharToString(sql_state));
354372

355373
EXPECT_FALSE(std::wstring(message).empty());
356374
}
@@ -362,9 +380,8 @@ TYPED_TEST(ErrorsTest, TestSQLErrorConnError) {
362380
// DM passes 512 as buffer length to SQLError.
363381

364382
// Attempt to set unsupported attribute
365-
SQLRETURN ret = SQLGetConnectAttr(this->conn, SQL_ATTR_TXN_ISOLATION, 0, 0, nullptr);
366-
367-
ASSERT_EQ(SQL_ERROR, ret);
383+
ASSERT_EQ(SQL_ERROR,
384+
SQLGetConnectAttr(this->conn, SQL_ATTR_TXN_ISOLATION, 0, 0, nullptr));
368385

369386
SQLWCHAR sql_state[6] = {0};
370387
SQLINTEGER native_error = 0;
@@ -378,7 +395,7 @@ TYPED_TEST(ErrorsTest, TestSQLErrorConnError) {
378395
EXPECT_EQ(100, native_error);
379396

380397
// optional feature not supported error state
381-
EXPECT_EQ(std::wstring(L"HYC00"), std::wstring(sql_state));
398+
EXPECT_EQ(kErrorStateHYC00, SqlWcharToString(sql_state));
382399

383400
EXPECT_FALSE(std::wstring(message).empty());
384401
}
@@ -399,14 +416,16 @@ TYPED_TEST(ErrorsTest, TestSQLErrorStmtError) {
399416
SQLINTEGER native_error = 0;
400417
SQLWCHAR message[SQL_MAX_MESSAGE_LENGTH] = {0};
401418
SQLSMALLINT message_length = 0;
402-
ASSERT_EQ(SQL_SUCCESS, SQLError(nullptr, nullptr, this->stmt, sql_state, &native_error,
403-
message, SQL_MAX_MESSAGE_LENGTH, &message_length));
419+
SQLRETURN ret = SQLError(nullptr, this->conn, this->stmt, sql_state, &native_error,
420+
message, SQL_MAX_MESSAGE_LENGTH, &message_length);
421+
422+
EXPECT_TRUE(ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO);
404423

405424
EXPECT_GT(message_length, 70);
406425

407426
EXPECT_EQ(100, native_error);
408427

409-
EXPECT_EQ(std::wstring(L"HY000"), std::wstring(sql_state));
428+
EXPECT_EQ(kErrorStateHY000, SqlWcharToString(sql_state));
410429

411430
EXPECT_FALSE(std::wstring(message).empty());
412431
}
@@ -434,20 +453,21 @@ TYPED_TEST(ErrorsTest, TestSQLErrorStmtWarning) {
434453
SQLINTEGER native_error = 0;
435454
SQLWCHAR message[SQL_MAX_MESSAGE_LENGTH] = {0};
436455
SQLSMALLINT message_length = 0;
437-
ASSERT_EQ(SQL_SUCCESS, SQLError(nullptr, nullptr, this->stmt, sql_state, &native_error,
438-
message, SQL_MAX_MESSAGE_LENGTH, &message_length));
456+
ASSERT_EQ(SQL_SUCCESS,
457+
SQLError(SQL_NULL_HENV, this->conn, this->stmt, sql_state, &native_error,
458+
message, SQL_MAX_MESSAGE_LENGTH, &message_length));
439459

440460
EXPECT_GT(message_length, 50);
441461

442462
EXPECT_EQ(1000100, native_error);
443463

444464
// Verify string truncation warning is reported
445-
EXPECT_EQ(std::wstring(L"01004"), std::wstring(sql_state));
465+
EXPECT_EQ(kErrorState01004, SqlWcharToString(sql_state));
446466

447467
EXPECT_FALSE(std::wstring(message).empty());
448468
}
449469

450-
TYPED_TEST(ErrorsOdbcV2Test, TestSQLErrorEnvErrorODBCVer2FromDriverManager) {
470+
TYPED_TEST(ErrorsOdbcV2Test, TestSQLErrorEnvErrorFromDriverManager) {
451471
// Test ODBC 2.0 API SQLError with ODBC ver 2.
452472
// Known Windows Driver Manager (DM) behavior:
453473
// When application passes buffer length greater than SQL_MAX_MESSAGE_LENGTH (512),
@@ -464,22 +484,34 @@ TYPED_TEST(ErrorsOdbcV2Test, TestSQLErrorEnvErrorODBCVer2FromDriverManager) {
464484
ASSERT_EQ(SQL_SUCCESS, SQLError(this->env, nullptr, nullptr, sql_state, &native_error,
465485
message, SQL_MAX_MESSAGE_LENGTH, &message_length));
466486

467-
EXPECT_GT(message_length, 50);
487+
EXPECT_GT(message_length, 40);
468488

469489
EXPECT_EQ(0, native_error);
470490

471491
// Function sequence error state from driver manager
472-
EXPECT_EQ(std::wstring(L"S1010"), std::wstring(sql_state));
492+
#ifdef _WIN32
493+
// Windows Driver Manager returns S1010
494+
EXPECT_EQ(kErrorStateS1010, SqlWcharToString(sql_state));
495+
#else
496+
// unix Driver Manager returns HY010
497+
EXPECT_EQ(kErrorStateHY010, SqlWcharToString(sql_state));
498+
#endif // _WIN32
473499

474500
EXPECT_FALSE(std::wstring(message).empty());
475501
}
476502

477-
TYPED_TEST(ErrorsOdbcV2Test, TestSQLErrorConnErrorODBCVer2) {
503+
#ifndef __APPLE__
504+
TYPED_TEST(ErrorsOdbcV2Test, TestSQLErrorConnError) {
478505
// Test ODBC 2.0 API SQLError with ODBC ver 2.
479506
// Known Windows Driver Manager (DM) behavior:
480507
// When application passes buffer length greater than SQL_MAX_MESSAGE_LENGTH (512),
481508
// DM passes 512 as buffer length to SQLError.
482509

510+
// Known macOS Driver Manager (DM) behavior:
511+
// Attempts to call SQLGetConnectOption without redirecting the API call to
512+
// SQLGetConnectAttr. SQLGetConnectOption is not implemented as it is not required by
513+
// macOS Excel.
514+
483515
// Attempt to set unsupported attribute
484516
ASSERT_EQ(SQL_ERROR,
485517
SQLGetConnectAttr(this->conn, SQL_ATTR_TXN_ISOLATION, 0, 0, nullptr));
@@ -496,12 +528,13 @@ TYPED_TEST(ErrorsOdbcV2Test, TestSQLErrorConnErrorODBCVer2) {
496528
EXPECT_EQ(100, native_error);
497529

498530
// optional feature not supported error state. Driver Manager maps state to S1C00
499-
EXPECT_EQ(std::wstring(L"S1C00"), std::wstring(sql_state));
531+
EXPECT_EQ(kErrorStateS1C00, SqlWcharToString(sql_state));
500532

501533
EXPECT_FALSE(std::wstring(message).empty());
502534
}
535+
#endif // __APPLE__
503536

504-
TYPED_TEST(ErrorsOdbcV2Test, TestSQLErrorStmtErrorODBCVer2) {
537+
TYPED_TEST(ErrorsOdbcV2Test, TestSQLErrorStmtError) {
505538
// Test ODBC 2.0 API SQLError with ODBC ver 2.
506539
// Known Windows Driver Manager (DM) behavior:
507540
// When application passes buffer length greater than SQL_MAX_MESSAGE_LENGTH (512),
@@ -525,12 +558,12 @@ TYPED_TEST(ErrorsOdbcV2Test, TestSQLErrorStmtErrorODBCVer2) {
525558
EXPECT_EQ(100, native_error);
526559

527560
// Driver Manager maps error state to S1000
528-
EXPECT_EQ(std::wstring(L"S1000"), std::wstring(sql_state));
561+
EXPECT_EQ(kErrorStateS1000, SqlWcharToString(sql_state));
529562

530563
EXPECT_FALSE(std::wstring(message).empty());
531564
}
532565

533-
TYPED_TEST(ErrorsOdbcV2Test, TestSQLErrorStmtWarningODBCVer2) {
566+
TYPED_TEST(ErrorsOdbcV2Test, TestSQLErrorStmtWarning) {
534567
// Test ODBC 2.0 API SQLError.
535568

536569
std::wstring wsql = L"SELECT 'VERY LONG STRING here' AS string_col;";
@@ -553,15 +586,16 @@ TYPED_TEST(ErrorsOdbcV2Test, TestSQLErrorStmtWarningODBCVer2) {
553586
SQLINTEGER native_error = 0;
554587
SQLWCHAR message[SQL_MAX_MESSAGE_LENGTH] = {0};
555588
SQLSMALLINT message_length = 0;
556-
ASSERT_EQ(SQL_SUCCESS, SQLError(nullptr, nullptr, this->stmt, sql_state, &native_error,
557-
message, SQL_MAX_MESSAGE_LENGTH, &message_length));
589+
ASSERT_EQ(SQL_SUCCESS,
590+
SQLError(SQL_NULL_HENV, this->conn, this->stmt, sql_state, &native_error,
591+
message, SQL_MAX_MESSAGE_LENGTH, &message_length));
558592

559593
EXPECT_GT(message_length, 50);
560594

561595
EXPECT_EQ(1000100, native_error);
562596

563597
// Verify string truncation warning is reported
564-
EXPECT_EQ(std::wstring(L"01004"), std::wstring(sql_state));
598+
EXPECT_EQ(kErrorState01004, SqlWcharToString(sql_state));
565599

566600
EXPECT_FALSE(std::wstring(message).empty());
567601
}

cpp/src/arrow/flight/sql/odbc/tests/odbc_test_suite.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,10 +237,12 @@ static constexpr std::string_view kErrorStateHY114 = "HY114";
237237
static constexpr std::string_view kErrorStateHY118 = "HY118";
238238
static constexpr std::string_view kErrorStateHYC00 = "HYC00";
239239
static constexpr std::string_view kErrorStateIM001 = "IM001";
240+
static constexpr std::string_view kErrorStateS1000 = "S1000";
240241
static constexpr std::string_view kErrorStateS1002 = "S1002";
241242
static constexpr std::string_view kErrorStateS1004 = "S1004";
242243
static constexpr std::string_view kErrorStateS1010 = "S1010";
243244
static constexpr std::string_view kErrorStateS1090 = "S1090";
245+
static constexpr std::string_view kErrorStateS1C00 = "S1C00";
244246

245247
/// Verify ODBC Error State
246248
void VerifyOdbcErrorState(SQLSMALLINT handle_type, SQLHANDLE handle,

0 commit comments

Comments
 (0)