Skip to content

Commit 3072a5f

Browse files
committed
fix handling the output conn str buff if too small (#194)
If the application provides an output buffer for the constructed connection string, the driver will currently return an error and thus fail the connection. The correct handling is however to apply truncation but return the number of characters available without trunctation. This commit works around swprintf() returning an error code, but otherwise correctly 0-terminating the destination buffer and not setting the errno. (cherry picked from commit ef5dccb) Merge changed to use 6.8 ES/SQL data types (test/connected_dbc.*).
1 parent 535e708 commit 3072a5f

File tree

7 files changed

+191
-111
lines changed

7 files changed

+191
-111
lines changed

driver/connect.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2748,6 +2748,9 @@ SQLRETURN EsSQLSetConnectAttrW(
27482748
RET_HDIAGS(dbc, SQL_STATE_HYC00);
27492749

27502750
#ifndef NDEBUG
2751+
/* MicroStrategy Desktop, Oracle BI invoked */
2752+
case 1041:
2753+
case 1042:
27512754
/* MS Access/Jet proprietary info type */
27522755
case 30002:
27532756
ERRH(dbc, "unsupported info type.");

driver/defs.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@
5757
#define ESODBC_MAX_IDENTIFIER_LEN SHRT_MAX
5858
/* "the relationship between the columns in the GROUP BY clause and the
5959
* nonaggregated columns in the select list" */
60-
#define ESODBC_GROUP_BY SQL_GB_NO_RELATION
60+
#define ESODBC_GROUP_BY SQL_GB_NO_RELATION
6161

6262
/* 20 = len("18446744073709551616"), 1 << (sizeof(uint64_t) * 8bits) */
6363
#define ESODBC_PRECISION_UINT64 20

driver/dsn.c

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -787,13 +787,19 @@ long TEST_API write_connection_string(esodbc_dsn_attrs_st *attrs,
787787
} else {
788788
format = WPFWP_LDESC "=" WPFWP_LDESC ";";
789789
}
790+
errno = 0;
790791
n = swprintf(szConnStrOut + pos, cchConnStrOutMax - pos,
791792
format, LWSTR(iter->kw), LWSTR(iter->val));
793+
/* on buffer too small, swprintf() will 0-terminate it,
794+
* return negative, but not set errno. */
792795
if (n < 0) {
793-
ERRN("failed to outprint connection string (keyword: "
794-
LWPDL ", room: %hd, position: %zu).",
795-
LWSTR(iter->kw), cchConnStrOutMax, pos);
796-
return -1;
796+
if (errno != 0) {
797+
ERRN("failed to print connection string (keyword: "
798+
LWPDL ", room: %hd, position: %zu).",
799+
LWSTR(iter->kw), cchConnStrOutMax, pos);
800+
return -1;
801+
}
802+
assert(szConnStrOut[cchConnStrOutMax - 1] == L'\0');
797803
}
798804
}
799805
}

driver/handles.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,8 @@ SQLRETURN EsSQLSetEnvAttr(SQLHENV EnvironmentHandle,
521521
// review of the options.
522522
case SQL_OV_ODBC2:
523523
case SQL_OV_ODBC3:
524+
WARNH(EnvironmentHandle, "application version %d not fully"
525+
" supported.", (intptr_t)Value);
524526
case SQL_OV_ODBC3_80:
525527
break;
526528
default:

test/connected_dbc.cc

Lines changed: 5 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -14,112 +14,13 @@ extern "C" {
1414

1515
#include "connected_dbc.h"
1616

17-
/*
18-
* Answer ES/SQL sends to SYS TYPES
19-
* TODO: (Changes: MINIMUM_SCALE changed from 0 to MAXIMUM_SCALE for:
20-
* HALF_FLOAT, SCALED_FLOAT, FLOAT, DOUBLE.)
21-
*/
22-
static const char systypes_answer[] = "\
23-
{\
24-
\"columns\": [\
25-
{\"name\": \"TYPE_NAME\", \"type\": \"keyword\"},\
26-
{\"name\": \"DATA_TYPE\", \"type\": \"integer\"},\
27-
{\"name\": \"PRECISION\", \"type\": \"integer\"},\
28-
{\"name\": \"LITERAL_PREFIX\", \"type\": \"keyword\"},\
29-
{\"name\": \"LITERAL_SUFFIX\", \"type\": \"keyword\"},\
30-
{\"name\": \"CREATE_PARAMS\", \"type\": \"keyword\"},\
31-
{\"name\": \"NULLABLE\", \"type\": \"short\"},\
32-
{\"name\": \"CASE_SENSITIVE\", \"type\": \"boolean\"},\
33-
{\"name\": \"SEARCHABLE\", \"type\": \"short\"},\
34-
{\"name\": \"UNSIGNED_ATTRIBUTE\", \"type\": \"boolean\"},\
35-
{\"name\": \"FIXED_PREC_SCALE\", \"type\": \"boolean\"},\
36-
{\"name\": \"AUTO_INCREMENT\", \"type\": \"boolean\"},\
37-
{\"name\": \"LOCAL_TYPE_NAME\", \"type\": \"keyword\"},\
38-
{\"name\": \"MINIMUM_SCALE\", \"type\": \"short\"},\
39-
{\"name\": \"MAXIMUM_SCALE\", \"type\": \"short\"},\
40-
{\"name\": \"SQL_DATA_TYPE\", \"type\": \"integer\"},\
41-
{\"name\": \"SQL_DATETIME_SUB\", \"type\": \"integer\"},\
42-
{\"name\": \"NUM_PREC_RADIX\", \"type\": \"integer\"},\
43-
{\"name\": \"INTERVAL_PRECISION\", \"type\": \"integer\"}\
44-
],\
45-
\"rows\": [\
46-
[\"BYTE\", -6, 3, \"'\", \"'\", null, 2, false, 3, false, false,\
47-
false, null, 0, 0, -6, 0, 10, null],\
48-
[\"LONG\", -5, 19, \"'\", \"'\", null, 2, false, 3, false, false,\
49-
false, null, 0, 0, -5, 0, 10, null],\
50-
[\"BINARY\", -3, 2147483647, \"'\", \"'\", null, 2, false, 3, true,\
51-
false, false, null, null, null, -3, 0, null, null],\
52-
[\"NULL\", 0, 0, \"'\", \"'\", null, 2, false, 3, true, false, false,\
53-
null, null, null, 0, 0, null, null],\
54-
[\"INTEGER\", 4, 10, \"'\", \"'\", null, 2, false, 3, false, false,\
55-
false, null, 0, 0, 4, 0, 10, null],\
56-
[\"SHORT\", 5, 5, \"'\", \"'\", null, 2, false, 3, false, false,\
57-
false, null, 0, 0, 5, 0, 10, null],\
58-
[\"HALF_FLOAT\", 6, 16, \"'\", \"'\", null, 2, false, 3, false, false,\
59-
false, null, 0, 16, 6, 0, 2, null],\
60-
[\"SCALED_FLOAT\", 6, 19, \"'\", \"'\", null, 2, false, 3, false,\
61-
false, false, null, 0, 19, 6, 0, 2, null],\
62-
[\"FLOAT\", 7, 7, \"'\", \"'\", null, 2, false, 3, false, false,\
63-
false, null, 0, 7, 7, 0, 2, null],\
64-
[\"DOUBLE\", 8, 15, \"'\", \"'\", null, 2, false, 3, false, false,\
65-
false, null, 0, 15, 8, 0, 2, null],\
66-
[\"KEYWORD\", 12, 256, \"'\", \"'\", null, 2, true, 3, true, false,\
67-
false, null, null, null, 12, 0, null, null],\
68-
[\"TEXT\", 12, 2147483647, \"'\", \"'\", null, 2, true, 3, true,\
69-
false, false, null, null, null, 12, 0, null, null],\
70-
[\"BOOLEAN\", 16, 1, \"'\", \"'\", null, 2, false, 3, true, false,\
71-
false, null, null, null, 16, 0, null, null],\
72-
[\"DATE\", 91, 10, \"'\", \"'\", null, 2, false, 3, true, false,\
73-
false, null, null, null, 91, 0, null, null],\
74-
[\"DATETIME\", 93, 24, \"'\", \"'\", null, 2, false, 3, true, false,\
75-
false, null, 3, 3, 9, 3, null, null],\
76-
[\"INTERVAL_YEAR\", 101, 7, \"'\", \"'\", null, 2, false, 3, true,\
77-
false, false, null, null, null, 101, 0, null, null],\
78-
[\"INTERVAL_MONTH\", 102, 7, \"'\", \"'\", null, 2, false, 3, true,\
79-
false, false, null, null, null, 102, 0, null, null],\
80-
[\"INTERVAL_DAY\", 103, 23, \"'\", \"'\", null, 2, false, 3, true,\
81-
false, false, null, null, null, 103, 0, null, null],\
82-
[\"INTERVAL_HOUR\", 104, 23, \"'\", \"'\", null, 2, false, 3, true,\
83-
false, false, null, null, null, 104, 0, null, null],\
84-
[\"INTERVAL_MINUTE\", 105, 23, \"'\", \"'\", null, 2, false, 3, true,\
85-
false, false, null, null, null, 105, 0, null, null],\
86-
[\"INTERVAL_SECOND\", 106, 23, \"'\", \"'\", null, 2, false, 3, true,\
87-
false, false, null, null, null, 106, 0, null, null],\
88-
[\"INTERVAL_YEAR_TO_MONTH\", 107, 7, \"'\", \"'\", null, 2, false, 3,\
89-
true, false, false, null, null, null, 107, 0, null, null],\
90-
[\"INTERVAL_DAY_TO_HOUR\", 108, 23, \"'\", \"'\", null, 2, false, 3,\
91-
true, false, false, null, null, null, 108, 0, null, null],\
92-
[\"INTERVAL_DAY_TO_MINUTE\", 109, 23, \"'\", \"'\", null, 2, false, 3,\
93-
true, false, false, null, null, null, 109, 0, null, null],\
94-
[\"INTERVAL_DAY_TO_SECOND\", 110, 23, \"'\", \"'\", null, 2, false, 3,\
95-
true, false, false, null, null, null, 110, 0, null, null],\
96-
[\"INTERVAL_HOUR_TO_MINUTE\", 111, 23, \"'\", \"'\", null, 2, false,\
97-
3, true, false, false, null, null, null, 111, 0, null, null],\
98-
[\"INTERVAL_HOUR_TO_SECOND\", 112, 23, \"'\", \"'\", null, 2, false,\
99-
3, true, false, false, null, null, null, 112, 0, null, null],\
100-
[\"INTERVAL_MINUTE_TO_SECOND\", 113, 23, \"'\", \"'\", null, 2, false,\
101-
3, true, false, false, null, null, null, 113, 0, null, null],\
102-
[\"UNSUPPORTED\", 1111, 0, \"'\", \"'\", null, 2, false, 3, true,\
103-
false, false, null, null, null, 1111, 0, null, null],\
104-
[\"OBJECT\", 2002, 0, \"'\", \"'\", null, 2, false, 3, true, false,\
105-
false, null, null, null, 2002, 0, null, null],\
106-
[\"NESTED\", 2002, 0, \"'\", \"'\", null, 2, false, 3, true, false,\
107-
false, null, null, null, 2002, 0, null, null]\
108-
]\
109-
}\
110-
";
111-
112-
/* minimal, valid connection string */
113-
static const SQLWCHAR connect_string[] = L"Driver=ElasticODBC";
114-
11517

11618
/*
11719
* Class will provide a "connected" DBC: the ES types are loaded.
11820
*/
11921
ConnectedDBC::ConnectedDBC()
12022
{
121-
SQLRETURN ret;
122-
cstr_st types;
23+
cstr_st types = {0};
12324

12425
ret = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env);
12526
assert(SQL_SUCCEEDED(ret));
@@ -131,14 +32,12 @@ ConnectedDBC::ConnectedDBC()
13132
ret = SQLAllocHandle(SQL_HANDLE_DBC, env, &dbc);
13233
assert(SQL_SUCCEEDED(ret));
13334

134-
135-
types.cnt = sizeof(systypes_answer) - 1;
136-
types.str = (SQLCHAR *)malloc(types.cnt);
35+
types.str = (SQLCHAR *)strdup(SYSTYPES_ANSWER);
13736
assert(types.str != NULL);
138-
memcpy(types.str, systypes_answer, types.cnt);
37+
types.cnt = sizeof(SYSTYPES_ANSWER) - 1;
13938

140-
ret = SQLDriverConnect(dbc, (SQLHWND)&types, (SQLWCHAR *)connect_string,
141-
sizeof(connect_string) / sizeof(connect_string[0]) - 1, NULL, 0, NULL,
39+
ret = SQLDriverConnect(dbc, (SQLHWND)&types, (SQLWCHAR *)CONNECT_STRING,
40+
sizeof(CONNECT_STRING) / sizeof(CONNECT_STRING[0]) - 1, NULL, 0, NULL,
14241
ESODBC_SQL_DRIVER_TEST);
14342
assert(SQL_SUCCEEDED(ret));
14443

test/connected_dbc.h

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,102 @@ extern "C" {
3535
ASSERT_EQ(strncmp((char *)_c1.str, (char *)_c2.str, _c1.cnt), 0); \
3636
} while (0)
3737

38+
/*
39+
* Answer ES/SQL sends to SYS TYPES
40+
* TODO: (Changes: MINIMUM_SCALE changed from 0 to MAXIMUM_SCALE for:
41+
* HALF_FLOAT, SCALED_FLOAT, FLOAT, DOUBLE.)
42+
*/
43+
#define SYSTYPES_ANSWER "\
44+
{\
45+
\"columns\": [\
46+
{\"name\": \"TYPE_NAME\", \"type\": \"keyword\"},\
47+
{\"name\": \"DATA_TYPE\", \"type\": \"integer\"},\
48+
{\"name\": \"PRECISION\", \"type\": \"integer\"},\
49+
{\"name\": \"LITERAL_PREFIX\", \"type\": \"keyword\"},\
50+
{\"name\": \"LITERAL_SUFFIX\", \"type\": \"keyword\"},\
51+
{\"name\": \"CREATE_PARAMS\", \"type\": \"keyword\"},\
52+
{\"name\": \"NULLABLE\", \"type\": \"short\"},\
53+
{\"name\": \"CASE_SENSITIVE\", \"type\": \"boolean\"},\
54+
{\"name\": \"SEARCHABLE\", \"type\": \"short\"},\
55+
{\"name\": \"UNSIGNED_ATTRIBUTE\", \"type\": \"boolean\"},\
56+
{\"name\": \"FIXED_PREC_SCALE\", \"type\": \"boolean\"},\
57+
{\"name\": \"AUTO_INCREMENT\", \"type\": \"boolean\"},\
58+
{\"name\": \"LOCAL_TYPE_NAME\", \"type\": \"keyword\"},\
59+
{\"name\": \"MINIMUM_SCALE\", \"type\": \"short\"},\
60+
{\"name\": \"MAXIMUM_SCALE\", \"type\": \"short\"},\
61+
{\"name\": \"SQL_DATA_TYPE\", \"type\": \"integer\"},\
62+
{\"name\": \"SQL_DATETIME_SUB\", \"type\": \"integer\"},\
63+
{\"name\": \"NUM_PREC_RADIX\", \"type\": \"integer\"},\
64+
{\"name\": \"INTERVAL_PRECISION\", \"type\": \"integer\"}\
65+
],\
66+
\"rows\": [\
67+
[\"BYTE\", -6, 3, \"'\", \"'\", null, 2, false, 3, false, false,\
68+
false, null, 0, 0, -6, 0, 10, null],\
69+
[\"LONG\", -5, 19, \"'\", \"'\", null, 2, false, 3, false, false,\
70+
false, null, 0, 0, -5, 0, 10, null],\
71+
[\"BINARY\", -3, 2147483647, \"'\", \"'\", null, 2, false, 3, true,\
72+
false, false, null, null, null, -3, 0, null, null],\
73+
[\"NULL\", 0, 0, \"'\", \"'\", null, 2, false, 3, true, false, false,\
74+
null, null, null, 0, 0, null, null],\
75+
[\"INTEGER\", 4, 10, \"'\", \"'\", null, 2, false, 3, false, false,\
76+
false, null, 0, 0, 4, 0, 10, null],\
77+
[\"SHORT\", 5, 5, \"'\", \"'\", null, 2, false, 3, false, false,\
78+
false, null, 0, 0, 5, 0, 10, null],\
79+
[\"HALF_FLOAT\", 6, 16, \"'\", \"'\", null, 2, false, 3, false, false,\
80+
false, null, 0, 16, 6, 0, 2, null],\
81+
[\"SCALED_FLOAT\", 6, 19, \"'\", \"'\", null, 2, false, 3, false,\
82+
false, false, null, 0, 19, 6, 0, 2, null],\
83+
[\"FLOAT\", 7, 7, \"'\", \"'\", null, 2, false, 3, false, false,\
84+
false, null, 0, 7, 7, 0, 2, null],\
85+
[\"DOUBLE\", 8, 15, \"'\", \"'\", null, 2, false, 3, false, false,\
86+
false, null, 0, 15, 8, 0, 2, null],\
87+
[\"KEYWORD\", 12, 256, \"'\", \"'\", null, 2, true, 3, true, false,\
88+
false, null, null, null, 12, 0, null, null],\
89+
[\"TEXT\", 12, 2147483647, \"'\", \"'\", null, 2, true, 3, true,\
90+
false, false, null, null, null, 12, 0, null, null],\
91+
[\"BOOLEAN\", 16, 1, \"'\", \"'\", null, 2, false, 3, true, false,\
92+
false, null, null, null, 16, 0, null, null],\
93+
[\"DATE\", 91, 10, \"'\", \"'\", null, 2, false, 3, true, false,\
94+
false, null, null, null, 91, 0, null, null],\
95+
[\"DATETIME\", 93, 24, \"'\", \"'\", null, 2, false, 3, true, false,\
96+
false, null, 3, 3, 9, 3, null, null],\
97+
[\"INTERVAL_YEAR\", 101, 7, \"'\", \"'\", null, 2, false, 3, true,\
98+
false, false, null, null, null, 101, 0, null, null],\
99+
[\"INTERVAL_MONTH\", 102, 7, \"'\", \"'\", null, 2, false, 3, true,\
100+
false, false, null, null, null, 102, 0, null, null],\
101+
[\"INTERVAL_DAY\", 103, 23, \"'\", \"'\", null, 2, false, 3, true,\
102+
false, false, null, null, null, 103, 0, null, null],\
103+
[\"INTERVAL_HOUR\", 104, 23, \"'\", \"'\", null, 2, false, 3, true,\
104+
false, false, null, null, null, 104, 0, null, null],\
105+
[\"INTERVAL_MINUTE\", 105, 23, \"'\", \"'\", null, 2, false, 3, true,\
106+
false, false, null, null, null, 105, 0, null, null],\
107+
[\"INTERVAL_SECOND\", 106, 23, \"'\", \"'\", null, 2, false, 3, true,\
108+
false, false, null, null, null, 106, 0, null, null],\
109+
[\"INTERVAL_YEAR_TO_MONTH\", 107, 7, \"'\", \"'\", null, 2, false, 3,\
110+
true, false, false, null, null, null, 107, 0, null, null],\
111+
[\"INTERVAL_DAY_TO_HOUR\", 108, 23, \"'\", \"'\", null, 2, false, 3,\
112+
true, false, false, null, null, null, 108, 0, null, null],\
113+
[\"INTERVAL_DAY_TO_MINUTE\", 109, 23, \"'\", \"'\", null, 2, false, 3,\
114+
true, false, false, null, null, null, 109, 0, null, null],\
115+
[\"INTERVAL_DAY_TO_SECOND\", 110, 23, \"'\", \"'\", null, 2, false, 3,\
116+
true, false, false, null, null, null, 110, 0, null, null],\
117+
[\"INTERVAL_HOUR_TO_MINUTE\", 111, 23, \"'\", \"'\", null, 2, false,\
118+
3, true, false, false, null, null, null, 111, 0, null, null],\
119+
[\"INTERVAL_HOUR_TO_SECOND\", 112, 23, \"'\", \"'\", null, 2, false,\
120+
3, true, false, false, null, null, null, 112, 0, null, null],\
121+
[\"INTERVAL_MINUTE_TO_SECOND\", 113, 23, \"'\", \"'\", null, 2, false,\
122+
3, true, false, false, null, null, null, 113, 0, null, null],\
123+
[\"UNSUPPORTED\", 1111, 0, \"'\", \"'\", null, 2, false, 3, true,\
124+
false, false, null, null, null, 1111, 0, null, null],\
125+
[\"OBJECT\", 2002, 0, \"'\", \"'\", null, 2, false, 3, true, false,\
126+
false, null, null, null, 2002, 0, null, null],\
127+
[\"NESTED\", 2002, 0, \"'\", \"'\", null, 2, false, 3, true, false,\
128+
false, null, null, null, 2002, 0, null, null]\
129+
]\
130+
}"
131+
132+
/* minimal, valid connection string */
133+
#define CONNECT_STRING L"Driver=ElasticODBC"
38134

39135
class ConnectedDBC {
40136
protected:

test/test_driverconnect.cc

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
7+
#include <gtest/gtest.h>
8+
#include "connected_dbc.h"
9+
10+
namespace test {
11+
12+
class DriverConnect : public ::testing::Test, public ConnectedDBC
13+
{
14+
protected:
15+
cstr_st types = {0};
16+
SQLHANDLE my_dbc;
17+
SQLSMALLINT out_avail = -1;
18+
19+
void SetUp() override
20+
{
21+
ret = SQLAllocHandle(SQL_HANDLE_DBC, env, &my_dbc);
22+
ASSERT_TRUE(SQL_SUCCEEDED(ret));
23+
24+
types.str = (SQLCHAR *)strdup(SYSTYPES_ANSWER);
25+
ASSERT_TRUE(types.str != NULL);
26+
types.cnt = sizeof(SYSTYPES_ANSWER) - 1;
27+
}
28+
29+
void TearDown() override
30+
{
31+
ret = SQLFreeHandle(SQL_HANDLE_DBC, my_dbc);
32+
ASSERT_TRUE(SQL_SUCCEEDED(ret));
33+
}
34+
};
35+
36+
TEST_F(DriverConnect, OutputCount)
37+
{
38+
ret = SQLDriverConnect(my_dbc, (SQLHWND)&types, (SQLWCHAR *)CONNECT_STRING,
39+
sizeof(CONNECT_STRING) / sizeof(CONNECT_STRING[0]) - 1, NULL, 0,
40+
&out_avail, ESODBC_SQL_DRIVER_TEST);
41+
ASSERT_TRUE(SQL_SUCCEEDED(ret));
42+
ASSERT_TRUE(0 < out_avail);
43+
}
44+
45+
TEST_F(DriverConnect, OutputZeroTerm)
46+
{
47+
static const size_t buff_sz = 1024;
48+
SQLWCHAR out_buff[buff_sz];
49+
50+
ret = SQLDriverConnect(my_dbc, (SQLHWND)&types, (SQLWCHAR *)CONNECT_STRING,
51+
sizeof(CONNECT_STRING) / sizeof(CONNECT_STRING[0]) - 1,
52+
out_buff, buff_sz, &out_avail, ESODBC_SQL_DRIVER_TEST);
53+
ASSERT_TRUE(SQL_SUCCEEDED(ret));
54+
ASSERT_TRUE(out_avail < buff_sz);
55+
ASSERT_EQ(out_buff[out_avail], (SQLWCHAR)L'\0');
56+
57+
}
58+
59+
TEST_F(DriverConnect, OutputTruncated)
60+
{
61+
static const size_t buff_sz = 3;
62+
SQLWCHAR out_buff[buff_sz];
63+
64+
ret = SQLDriverConnect(my_dbc, (SQLHWND)&types, (SQLWCHAR *)CONNECT_STRING,
65+
sizeof(CONNECT_STRING) / sizeof(CONNECT_STRING[0]) - 1,
66+
out_buff, buff_sz, &out_avail, ESODBC_SQL_DRIVER_TEST);
67+
ASSERT_TRUE(SQL_SUCCEEDED(ret));
68+
ASSERT_TRUE(buff_sz < out_avail);
69+
ASSERT_EQ(out_buff[buff_sz - 1], (SQLWCHAR)L'\0');
70+
71+
}
72+
73+
} // test namespace
74+

0 commit comments

Comments
 (0)