Skip to content

Commit 69243d4

Browse files
committed
fix length read from app ptr when param binding (#173)
This commit fixes the length handling of received wide-char strings as parameters: the indicator-length pointer of the API call provides the octet count, so the lenght needs to be divided by wide-char size. Besides a couple of tests for the fix, the commit adds a new test on null generation (both of non-NULL and NULL types). (cherry picked from commit 29376ec) Resolved conflicts: - driver/convert.c Resolved partial merge: - test/test_conversion_c2sql_varchar.cc
1 parent 5ecbaa5 commit 69243d4

File tree

3 files changed

+109
-4
lines changed

3 files changed

+109
-4
lines changed

driver/convert.c

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3210,7 +3210,6 @@ static BOOL xstr_to_number(esodbc_stmt_st *stmt, void *data_ptr,
32103210
SQLRETURN c2sql_null(esodbc_rec_st *arec,
32113211
esodbc_rec_st *irec, char *dest, size_t *len)
32123212
{
3213-
assert(irec->concise_type == ESODBC_SQL_NULL);
32143213
if (dest) {
32153214
memcpy(dest, JSON_VAL_NULL, sizeof(JSON_VAL_NULL) - /*\0*/1);
32163215
}
@@ -4121,6 +4120,37 @@ SQLRETURN c2sql_interval(esodbc_rec_st *arec, esodbc_rec_st *irec,
41214120
# undef ASSIGN_SIGNED
41224121
}
41234122

4123+
static inline SQLLEN get_octet_len(SQLLEN *octet_len_ptr, void *data_ptr,
4124+
BOOL wide)
4125+
{
4126+
SQLLEN cnt;
4127+
4128+
assert(data_ptr);
4129+
4130+
if (! octet_len_ptr) {
4131+
/* "If [...] is a null pointer, the driver assumes that all input
4132+
* parameter values are non-NULL and that character and binary data is
4133+
* null-terminated." */
4134+
cnt = wide ? wcslen((wchar_t *)data_ptr) : strlen((char *)data_ptr);
4135+
} else {
4136+
cnt = *octet_len_ptr;
4137+
switch (cnt) {
4138+
case SQL_NTSL:
4139+
cnt = wide ? wcslen((wchar_t *)data_ptr) :
4140+
strlen((char *)data_ptr);
4141+
break;
4142+
case SQL_NULL_DATA:
4143+
BUG("converting SQL_NULL_DATA");
4144+
cnt = -1; /* UTF16/8 will fail */
4145+
break;
4146+
default: /* get characters count from octets count */
4147+
cnt /= wide ? sizeof(SQLWCHAR) : sizeof(SQLCHAR);
4148+
}
4149+
}
4150+
4151+
return cnt;
4152+
}
4153+
41244154
static SQLRETURN c2sql_cstr2qstr(esodbc_rec_st *arec, esodbc_rec_st *irec,
41254155
SQLULEN pos, char *dest, size_t *len)
41264156
{
@@ -4133,7 +4163,7 @@ static SQLRETURN c2sql_cstr2qstr(esodbc_rec_st *arec, esodbc_rec_st *irec,
41334163
/* pointer to app's buffer */
41344164
data_ptr = deferred_address(SQL_DESC_DATA_PTR, pos, arec);
41354165

4136-
cnt = octet_len_ptr ? *octet_len_ptr : strlen((char *)data_ptr);
4166+
cnt = get_octet_len(octet_len_ptr, data_ptr, /*wide*/FALSE);
41374167

41384168
if (dest) {
41394169
*dest = '"';
@@ -4167,7 +4197,7 @@ static SQLRETURN c2sql_wstr2qstr(esodbc_rec_st *arec, esodbc_rec_st *irec,
41674197
/* pointer to app's buffer */
41684198
data_ptr = deferred_address(SQL_DESC_DATA_PTR, pos, arec);
41694199

4170-
cnt = octet_len_ptr ? *octet_len_ptr : wcslen((wchar_t *)data_ptr);
4200+
cnt = get_octet_len(octet_len_ptr, data_ptr, /*wide*/TRUE);
41714201

41724202
if (dest) {
41734203
*dest = '"';
@@ -4186,7 +4216,7 @@ static SQLRETURN c2sql_wstr2qstr(esodbc_rec_st *arec, esodbc_rec_st *irec,
41864216
octets = WCS2U8((wchar_t *)data_ptr, (int)cnt, dest + !!dest,
41874217
dest ? INT_MAX : 0);
41884218
if ((err = GetLastError())) {
4189-
ERRH(stmt, "converting to multibyte string failed: %d", err);
4219+
ERRH(stmt, "converting to multibyte string failed: 0x%x", err);
41904220
RET_HDIAGS(stmt, SQL_STATE_HY000);
41914221
}
41924222
} else {

test/test_conversion_c2sql_null.cc

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
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 ConvertC2SQL_Null : public ::testing::Test, public ConnectedDBC {
13+
};
14+
15+
16+
TEST_F(ConvertC2SQL_Null, CStr2Boolean_null)
17+
{
18+
prepareStatement();
19+
20+
SQLCHAR val[] = "1";
21+
SQLLEN osize = SQL_NULL_DATA;
22+
ret = SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR,
23+
ESODBC_SQL_BOOLEAN, /*size*/0, /*decdigits*/0, val,
24+
sizeof(val) - /*\0*/1, &osize);
25+
ASSERT_TRUE(SQL_SUCCEEDED(ret));
26+
27+
assertRequest("[{\"type\": \"BOOLEAN\", \"value\": null}]");
28+
}
29+
30+
TEST_F(ConvertC2SQL_Null, WStr2Null)
31+
{
32+
prepareStatement();
33+
34+
SQLWCHAR val[] = L"0X";
35+
ret = SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_WCHAR,
36+
ESODBC_SQL_NULL, /*size*/0, /*decdigits*/0, val, 0, NULL);
37+
ASSERT_TRUE(SQL_SUCCEEDED(ret));
38+
39+
assertRequest("[{\"type\": \"NULL\", \"value\": null}]");
40+
}
41+
42+
43+
} // test namespace
44+
45+
/* vim: set noet fenc=utf-8 ff=dos sts=0 sw=4 ts=4 : */

test/test_conversion_c2sql_varchar.cc

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,21 @@ TEST_F(ConvertC2SQL_Varchar, WStr2Varchar_ansi_jsonescape)
141141
ASSERT_CSTREQ(buff, expect);
142142
}
143143

144+
TEST_F(ConvertC2SQL_Varchar, CStr2Varchar_jsonescape_oct_len_ptr)
145+
{
146+
prepareStatement();
147+
148+
SQLCHAR val[] = "START_{xxx}=\"yyy\"\r__END";
149+
SQLLEN octet_len = strlen((char *)val);
150+
ret = SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR,
151+
SQL_VARCHAR, /*size*/35, /*decdigits*/0, val, sizeof(val),
152+
&octet_len);
153+
ASSERT_TRUE(SQL_SUCCEEDED(ret));
154+
155+
//assertRequest("[{\"type\": \"KEYWORD\", "
156+
// "\"value\": \"START_{xxx}=\\\"yyy\\\"\\r__END\"}]");
157+
}
158+
144159
/* note: test name used in test */
145160
TEST_F(ConvertC2SQL_Varchar, CStr2Varchar_jsonescape)
146161
{
@@ -189,6 +204,21 @@ TEST_F(ConvertC2SQL_Varchar, WStr2Varchar_u8_jsonescape)
189204
ASSERT_CSTREQ(buff, expect);
190205
}
191206

207+
TEST_F(ConvertC2SQL_Varchar, WStr2Varchar_u8_fullescape_oct_len_ptr)
208+
{
209+
prepareStatement();
210+
211+
SQLWCHAR val[] = L"äöüÄÖÜ";
212+
SQLLEN octet_len = SQL_NTSL;
213+
ret = SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_WCHAR,
214+
SQL_VARCHAR, /*size*/35, /*decdigits*/0, val, sizeof(val),
215+
&octet_len);
216+
ASSERT_TRUE(SQL_SUCCEEDED(ret));
217+
218+
//assertRequest("[{\"type\": \"KEYWORD\", "
219+
// "\"value\": \"\u00E4\u00F6\u00FC\u00C4\u00D6\u00DC\"}]");
220+
}
221+
192222
/* note: test name used in test */
193223
TEST_F(ConvertC2SQL_Varchar, WStr2Varchar_u8_fullescape)
194224
{

0 commit comments

Comments
 (0)