Skip to content

Commit

Permalink
fix length read from app ptr when param binding (#173)
Browse files Browse the repository at this point in the history
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 conflict: s/WAPI_ERRNO/WCS2U8_ERRNO/ .
  • Loading branch information
bpintea committed Aug 28, 2019
1 parent 8dbd16a commit 26fe33c
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 5 deletions.
40 changes: 35 additions & 5 deletions driver/convert.c
Original file line number Diff line number Diff line change
Expand Up @@ -3664,7 +3664,6 @@ static BOOL xstr_to_number(esodbc_stmt_st *stmt, void *data_ptr,
SQLRETURN c2sql_null(esodbc_rec_st *arec,
esodbc_rec_st *irec, char *dest, size_t *len)
{
assert(irec->concise_type == ESODBC_SQL_NULL);
if (dest) {
memcpy(dest, JSON_VAL_NULL, sizeof(JSON_VAL_NULL) - /*\0*/1);
}
Expand Down Expand Up @@ -4615,6 +4614,37 @@ SQLRETURN c2sql_interval(esodbc_rec_st *arec, esodbc_rec_st *irec,
# undef ASSIGN_SIGNED
}

static inline SQLLEN get_octet_len(SQLLEN *octet_len_ptr, void *data_ptr,
BOOL wide)
{
SQLLEN cnt;

assert(data_ptr);

if (! octet_len_ptr) {
/* "If [...] is a null pointer, the driver assumes that all input
* parameter values are non-NULL and that character and binary data is
* null-terminated." */
cnt = wide ? wcslen((wchar_t *)data_ptr) : strlen((char *)data_ptr);
} else {
cnt = *octet_len_ptr;
switch (cnt) {
case SQL_NTSL:
cnt = wide ? wcslen((wchar_t *)data_ptr) :
strlen((char *)data_ptr);
break;
case SQL_NULL_DATA:
BUG("converting SQL_NULL_DATA");
cnt = -1; /* UTF16/8 will fail */
break;
default: /* get characters count from octets count */
cnt /= wide ? sizeof(SQLWCHAR) : sizeof(SQLCHAR);
}
}

return cnt;
}

static SQLRETURN c2sql_cstr2qstr(esodbc_rec_st *arec, esodbc_rec_st *irec,
SQLULEN pos, char *dest, size_t *len)
{
Expand All @@ -4627,7 +4657,7 @@ static SQLRETURN c2sql_cstr2qstr(esodbc_rec_st *arec, esodbc_rec_st *irec,
/* pointer to app's buffer */
data_ptr = deferred_address(SQL_DESC_DATA_PTR, pos, arec);

cnt = octet_len_ptr ? *octet_len_ptr : strlen((char *)data_ptr);
cnt = get_octet_len(octet_len_ptr, data_ptr, /*wide*/FALSE);

if (dest) {
*dest = '"';
Expand Down Expand Up @@ -4661,7 +4691,7 @@ static SQLRETURN c2sql_wstr2qstr(esodbc_rec_st *arec, esodbc_rec_st *irec,
/* pointer to app's buffer */
data_ptr = deferred_address(SQL_DESC_DATA_PTR, pos, arec);

cnt = octet_len_ptr ? *octet_len_ptr : wcslen((wchar_t *)data_ptr);
cnt = get_octet_len(octet_len_ptr, data_ptr, /*wide*/TRUE);

if (dest) {
*dest = '"';
Expand All @@ -4679,8 +4709,8 @@ static SQLRETURN c2sql_wstr2qstr(esodbc_rec_st *arec, esodbc_rec_st *irec,
SetLastError(0);
octets = WCS2U8((wchar_t *)data_ptr, (int)cnt, dest + !!dest,
dest ? INT_MAX : 0);
if ((err = GetLastError())) {
ERRH(stmt, "converting to multibyte string failed: %d", err);
if ((err = WCS2U8_ERRNO()) != ERROR_SUCCESS) {
ERRH(stmt, "converting to multibyte string failed: 0x%x", err);
RET_HDIAGS(stmt, SQL_STATE_HY000);
}
} else {
Expand Down
45 changes: 45 additions & 0 deletions test/test_conversion_c2sql_null.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

#include <gtest/gtest.h>
#include "connected_dbc.h"

namespace test {

class ConvertC2SQL_Null : public ::testing::Test, public ConnectedDBC {
};


TEST_F(ConvertC2SQL_Null, CStr2Boolean_null)
{
prepareStatement();

SQLCHAR val[] = "1";
SQLLEN osize = SQL_NULL_DATA;
ret = SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR,
ESODBC_SQL_BOOLEAN, /*size*/0, /*decdigits*/0, val,
sizeof(val) - /*\0*/1, &osize);
ASSERT_TRUE(SQL_SUCCEEDED(ret));

assertRequest("[{\"type\": \"BOOLEAN\", \"value\": null}]");
}

TEST_F(ConvertC2SQL_Null, WStr2Null)
{
prepareStatement();

SQLWCHAR val[] = L"0X";
ret = SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_WCHAR,
ESODBC_SQL_NULL, /*size*/0, /*decdigits*/0, val, 0, NULL);
ASSERT_TRUE(SQL_SUCCEEDED(ret));

assertRequest("[{\"type\": \"NULL\", \"value\": null}]");
}


} // test namespace

/* vim: set noet fenc=utf-8 ff=dos sts=0 sw=4 ts=4 : */
30 changes: 30 additions & 0 deletions test/test_conversion_c2sql_varchar.cc
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,21 @@ TEST_F(ConvertC2SQL_Varchar, WStr2Varchar_ansi_jsonescape)
"\"value\": \"START_{xxx}=\\\"yyy\\\"\\r__END\"}]");
}

TEST_F(ConvertC2SQL_Varchar, CStr2Varchar_jsonescape_oct_len_ptr)
{
prepareStatement();

SQLCHAR val[] = "START_{xxx}=\"yyy\"\r__END";
SQLLEN octet_len = strlen((char *)val);
ret = SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR,
SQL_VARCHAR, /*size*/35, /*decdigits*/0, val, sizeof(val),
&octet_len);
ASSERT_TRUE(SQL_SUCCEEDED(ret));

assertRequest("[{\"type\": \"KEYWORD\", "
"\"value\": \"START_{xxx}=\\\"yyy\\\"\\r__END\"}]");
}

/* note: test name used in test */
TEST_F(ConvertC2SQL_Varchar, CStr2Varchar_jsonescape)
{
Expand Down Expand Up @@ -115,6 +130,21 @@ TEST_F(ConvertC2SQL_Varchar, WStr2Varchar_u8_jsonescape)
"\"value\": \"START_\\\"A\u00C4o\u00F6U\u00FC\\\"__END\"}]");
}

TEST_F(ConvertC2SQL_Varchar, WStr2Varchar_u8_fullescape_oct_len_ptr)
{
prepareStatement();

SQLWCHAR val[] = L"äöüÄÖÜ";
SQLLEN octet_len = SQL_NTSL;
ret = SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_WCHAR,
SQL_VARCHAR, /*size*/35, /*decdigits*/0, val, sizeof(val),
&octet_len);
ASSERT_TRUE(SQL_SUCCEEDED(ret));

assertRequest("[{\"type\": \"KEYWORD\", "
"\"value\": \"\u00E4\u00F6\u00FC\u00C4\u00D6\u00DC\"}]");
}

/* note: test name used in test */
TEST_F(ConvertC2SQL_Varchar, WStr2Varchar_u8_fullescape)
{
Expand Down

0 comments on commit 26fe33c

Please sign in to comment.