Skip to content

Commit 2459d3f

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 245a897 commit 2459d3f

File tree

5 files changed

+115
-4
lines changed

5 files changed

+115
-4
lines changed

driver/catalogue.c

+33
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,36 @@ SQLRETURN EsSQLStatisticsW(
9494
# undef STATISTICS_EMPTY
9595
}
9696

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

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

driver/catalogue.h

+1
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

+39-3
Original file line numberDiff line numberDiff line change
@@ -1528,6 +1528,13 @@ void cleanup_dbc(esodbc_dbc_st *dbc)
15281528
dbc->srv_ver.string.str = NULL;
15291529
dbc->srv_ver.string.cnt = 0;
15301530
}
1531+
if (dbc->catalog.str) {
1532+
free(dbc->catalog.str);
1533+
dbc->catalog.str = NULL;
1534+
dbc->catalog.cnt = 0;
1535+
} else {
1536+
assert(dbc->catalog.cnt == 0);
1537+
}
15311538

15321539
assert(dbc->abuff == NULL);
15331540
cleanup_curl(dbc);
@@ -3082,7 +3089,37 @@ SQLRETURN EsSQLDisconnect(SQLHDBC ConnectionHandle)
30823089
return SQL_SUCCESS;
30833090
}
30843091

3085-
3092+
/* ES/SQL doesn't support catalogs (yet). This function checks that a
3093+
* previously retrieved (and cached) catalog value is the same with what the
3094+
* app currently tries to set it to.
3095+
* Ideally, the app provided value would be cached here too (as per the spec:
3096+
* "SQL_ATTR_CURRENT_CATALOG can be set before or after connecting"), in case
3097+
* there's no connection "established" yet and checked at "establishment"
3098+
* time. But there's no client reported yet setting a catalog value before
3099+
* connecting. */
3100+
static SQLRETURN check_catalog_name(esodbc_dbc_st *dbc, SQLWCHAR *name,
3101+
SQLINTEGER len)
3102+
{
3103+
wstr_st catalog;
3104+
catalog.str = name;
3105+
if (len < 0) {
3106+
catalog.cnt = wcslen(name);
3107+
} else {
3108+
catalog.cnt = (size_t)len;
3109+
}
3110+
if (! EQ_WSTR(&dbc->catalog, &catalog)) {
3111+
if (! dbc->catalog.cnt) {
3112+
/* this will happen if the app tries to set a value that it
3113+
* discovered over a different connection.
3114+
* TODO on a first reported issue. */
3115+
WARNH(dbc, "connection's current catalog not yet set!");
3116+
}
3117+
ERRH(dbc, "setting catalog name not supported.");
3118+
RET_HDIAGS(dbc, SQL_STATE_HYC00);
3119+
}
3120+
WARNH(dbc, "ignoring attempt to set the current catalog.");
3121+
return SQL_SUCCESS;
3122+
}
30863123

30873124
/*
30883125
* https://docs.microsoft.com/en-us/sql/odbc/reference/develop-app/unicode-drivers :
@@ -3222,8 +3259,7 @@ SQLRETURN EsSQLSetConnectAttrW(
32223259
/* string should be 0-term'd */
32233260
0 <= StringLength ? StringLength : SHRT_MAX,
32243261
(SQLWCHAR *)Value);
3225-
ERRH(dbc, "setting catalog name not supported.");
3226-
RET_HDIAGS(dbc, SQL_STATE_HYC00);
3262+
return check_catalog_name(dbc, (SQLWCHAR *)Value, StringLength);
32273263

32283264
case SQL_ATTR_TRACE:
32293265
case SQL_ATTR_TRACEFILE: /* DM-only */

driver/handles.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -131,9 +131,10 @@ typedef struct struct_dbc {
131131

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

test/test_driverconnect.cc

+40
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)