Skip to content

Commit ff16632

Browse files
committed
Fix: allow (re)setting the current catalog (#212)
* allow (re)setting the current catalog This commit allows the application set the value of the current catalog attribute, in case this value is the same with what the driver had previously returned for this attribute. This currently only works if the attribute had been retrieved before setting, on the same connection; specifically, it won't work when this would be set as a pre-connection attribute. (cherry picked from commit 279c485)
1 parent eab7866 commit ff16632

File tree

5 files changed

+115
-4
lines changed

5 files changed

+115
-4
lines changed

driver/catalogue.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,36 @@ SQLRETURN EsSQLStatisticsW(
9393
# undef STATISTICS_EMPTY
9494
}
9595

96+
BOOL TEST_API set_current_catalog(esodbc_dbc_st *dbc, wstr_st *catalog)
97+
{
98+
if (dbc->catalog.cnt) {
99+
DBGH(dbc, "catalog already set to `" LWPDL "`.", LWSTR(&dbc->catalog));
100+
if (! EQ_WSTR(&dbc->catalog, catalog)) {
101+
/* this should never happen, as cluster's name is not updateable
102+
* on the fly. */
103+
ERRH(dbc, "overwriting previously set catalog value!");
104+
free(dbc->catalog.str);
105+
dbc->catalog.str = NULL;
106+
dbc->catalog.cnt = 0;
107+
} else {
108+
return FALSE;
109+
}
110+
}
111+
if (! catalog->cnt) {
112+
WARNH(dbc, "attempting to set catalog name to empty value.");
113+
return FALSE;
114+
}
115+
if (! (dbc->catalog.str = malloc((catalog->cnt + 1) * sizeof(SQLWCHAR)))) {
116+
ERRNH(dbc, "OOM for %zu wchars.", catalog->cnt + 1);
117+
return FALSE;
118+
}
119+
wmemcpy(dbc->catalog.str, catalog->str, catalog->cnt);
120+
dbc->catalog.str[catalog->cnt] = L'\0';
121+
dbc->catalog.cnt = catalog->cnt;
122+
INFOH(dbc, "current catalog name: `" LWPDL "`.", LWSTR(&dbc->catalog));
123+
124+
return TRUE;
125+
}
96126

97127
/* writes into 'dest', of size 'room', the current requested attr. of 'dbc'.
98128
* returns negative on error, or the char count written otherwise */
@@ -174,6 +204,9 @@ SQLSMALLINT fetch_server_attr(esodbc_dbc_st *dbc, SQLINTEGER attr_id,
174204
/* 0-term room left out when binding */
175205
buff[attr_val.cnt] = L'\0'; /* write_wstr() expects the 0-term */
176206
}
207+
if (attr_id == SQL_ATTR_CURRENT_CATALOG) {
208+
set_current_catalog(dbc, &attr_val);
209+
}
177210
}
178211
DBGH(dbc, "attribute %ld value: `" LWPDL "`.", attr_id, LWSTR(&attr_val));
179212

driver/catalogue.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
SQLSMALLINT fetch_server_attr(esodbc_dbc_st *dbc, SQLINTEGER attr_id,
1515
SQLWCHAR *dest, SQLSMALLINT room);
16+
BOOL TEST_API set_current_catalog(esodbc_dbc_st *dbc, wstr_st *catalog);
1617

1718

1819
SQLRETURN EsSQLStatisticsW(

driver/connect.c

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1196,6 +1196,13 @@ void cleanup_dbc(esodbc_dbc_st *dbc)
11961196
dbc->srv_ver.string.str = NULL;
11971197
dbc->srv_ver.string.cnt = 0;
11981198
}
1199+
if (dbc->catalog.str) {
1200+
free(dbc->catalog.str);
1201+
dbc->catalog.str = NULL;
1202+
dbc->catalog.cnt = 0;
1203+
} else {
1204+
assert(dbc->catalog.cnt == 0);
1205+
}
11991206

12001207
assert(dbc->abuff == NULL);
12011208
cleanup_curl(dbc);
@@ -2595,7 +2602,37 @@ SQLRETURN EsSQLDisconnect(SQLHDBC ConnectionHandle)
25952602
return SQL_SUCCESS;
25962603
}
25972604

2598-
2605+
/* ES/SQL doesn't support catalogs (yet). This function checks that a
2606+
* previously retrieved (and cached) catalog value is the same with what the
2607+
* app currently tries to set it to.
2608+
* Ideally, the app provided value would be cached here too (as per the spec:
2609+
* "SQL_ATTR_CURRENT_CATALOG can be set before or after connecting"), in case
2610+
* there's no connection "established" yet and checked at "establishment"
2611+
* time. But there's no client reported yet setting a catalog value before
2612+
* connecting. */
2613+
static SQLRETURN check_catalog_name(esodbc_dbc_st *dbc, SQLWCHAR *name,
2614+
SQLINTEGER len)
2615+
{
2616+
wstr_st catalog;
2617+
catalog.str = name;
2618+
if (len < 0) {
2619+
catalog.cnt = wcslen(name);
2620+
} else {
2621+
catalog.cnt = (size_t)len;
2622+
}
2623+
if (! EQ_WSTR(&dbc->catalog, &catalog)) {
2624+
if (! dbc->catalog.cnt) {
2625+
/* this will happen if the app tries to set a value that it
2626+
* discovered over a different connection.
2627+
* TODO on a first reported issue. */
2628+
WARNH(dbc, "connection's current catalog not yet set!");
2629+
}
2630+
ERRH(dbc, "setting catalog name not supported.");
2631+
RET_HDIAGS(dbc, SQL_STATE_HYC00);
2632+
}
2633+
WARNH(dbc, "ignoring attempt to set the current catalog.");
2634+
return SQL_SUCCESS;
2635+
}
25992636

26002637
/*
26012638
* https://docs.microsoft.com/en-us/sql/odbc/reference/develop-app/unicode-drivers :
@@ -2735,8 +2772,7 @@ SQLRETURN EsSQLSetConnectAttrW(
27352772
/* string should be 0-term'd */
27362773
0 <= StringLength ? StringLength : SHRT_MAX,
27372774
(SQLWCHAR *)Value);
2738-
ERRH(dbc, "setting catalog name not supported.");
2739-
RET_HDIAGS(dbc, SQL_STATE_HYC00);
2775+
return check_catalog_name(dbc, (SQLWCHAR *)Value, StringLength);
27402776

27412777
case SQL_ATTR_TRACE:
27422778
case SQL_ATTR_TRACEFILE: /* DM-only */

driver/handles.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,9 +130,10 @@ typedef struct struct_dbc {
130130

131131
wstr_st dsn; /* data source name SQLGetInfo(SQL_DATA_SOURCE_NAME) */
132132
wstr_st server; /* ~ name; requested with SQLGetInfo(SQL_SERVER_NAME) */
133+
wstr_st catalog; /* cached value; checked against if app setting it */
133134
union {
134135
wstr_st string; /* version: SQLGetInfo(SQL_DBMS_VER) */
135-
unsigned char checking; /* first letter of DSN config option */
136+
unsigned char checking; /* first letter of DSN config option value */
136137
} srv_ver; /* server version */
137138
cstr_st url; /* SQL URL (posts) */
138139
cstr_st close_url; /* SQL close URL (posts) */

test/test_driverconnect.cc

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@
77
#include <gtest/gtest.h>
88
#include "connected_dbc.h"
99

10+
extern "C" {
11+
#include "catalogue.h" /* set_current_catalog() */
12+
}
13+
1014
namespace test {
1115

1216
class DriverConnect : public ::testing::Test, public ConnectedDBC
@@ -70,5 +74,41 @@ TEST_F(DriverConnect, OutputTruncated)
7074

7175
}
7276

77+
TEST_F(DriverConnect, ReinitCurrentCatalog)
78+
{
79+
ret = SQLDriverConnect(my_dbc, (SQLHWND)&types, (SQLWCHAR *)CONNECT_STRING,
80+
sizeof(CONNECT_STRING) / sizeof(CONNECT_STRING[0]) - 1, NULL, 0,
81+
&out_avail, ESODBC_SQL_DRIVER_TEST);
82+
ASSERT_TRUE(SQL_SUCCEEDED(ret));
83+
84+
esodbc_dbc_st *dbc = (esodbc_dbc_st *)my_dbc;
85+
wstr_st crr_cat = WSTR_INIT("crr_catalog");
86+
ASSERT_TRUE(set_current_catalog(dbc, &crr_cat));
87+
ASSERT_FALSE(set_current_catalog(dbc, &crr_cat));
88+
89+
wstr_st other_cat = WSTR_INIT("other_catalog");
90+
ASSERT_TRUE(set_current_catalog(dbc, &other_cat));
91+
}
92+
93+
TEST_F(DriverConnect, ResetCurrentCatalog)
94+
{
95+
ret = SQLDriverConnect(my_dbc, (SQLHWND)&types, (SQLWCHAR *)CONNECT_STRING,
96+
sizeof(CONNECT_STRING) / sizeof(CONNECT_STRING[0]) - 1, NULL, 0,
97+
&out_avail, ESODBC_SQL_DRIVER_TEST);
98+
ASSERT_TRUE(SQL_SUCCEEDED(ret));
99+
100+
esodbc_dbc_st *dbc = (esodbc_dbc_st *)my_dbc;
101+
wstr_st crr_cat = WSTR_INIT("crr_catalog");
102+
ASSERT_TRUE(set_current_catalog(dbc, &crr_cat));
103+
ASSERT_TRUE(SQL_SUCCEEDED(SQLSetConnectAttrW(my_dbc,
104+
SQL_ATTR_CURRENT_CATALOG, (SQLPOINTER)crr_cat.str,
105+
(SQLINTEGER)crr_cat.cnt)));
106+
107+
wstr_st other_cat = WSTR_INIT("other_catalog");
108+
ASSERT_FALSE(SQL_SUCCEEDED(SQLSetConnectAttrW(my_dbc,
109+
SQL_ATTR_CURRENT_CATALOG, (SQLPOINTER)other_cat.str,
110+
(SQLINTEGER)other_cat.cnt)));
111+
}
112+
73113
} // test namespace
74114

0 commit comments

Comments
 (0)