Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
9095b2a
fix encoding
shivamd-gpartner Apr 27, 2026
cde311b
fix the encodings all places
shivamd-gpartner Apr 28, 2026
aaf978d
upload on git
shivamd-gpartner Apr 30, 2026
a38c156
more logging
shivamd-gpartner May 4, 2026
5bce456
cleaned logs
shivamd-gpartner May 6, 2026
c0f23a0
removed redundant code
shivamd-gpartner May 6, 2026
1528a67
test
shivamd-gpartner May 6, 2026
84473c8
added logs
shivamd-gpartner May 12, 2026
d2f2d9c
Revert "added logs"
shivamd-gpartner May 12, 2026
fe599de
Revert "test"
shivamd-gpartner May 12, 2026
1019100
revert the pipeline changes
shivamd-gpartner May 13, 2026
0a0bb84
Revert "revert the pipeline changes"
shivamd-gpartner May 13, 2026
8860ba6
added debug prints
shivamd-gpartner May 13, 2026
a486d7b
hide the implementation
shivamd-gpartner May 14, 2026
3c01515
revert WriteWideToWireBuffer function
NeerajDwivedii May 15, 2026
c7c9653
removed more code
shivamd-gpartner May 15, 2026
71981b2
Revert "hide the implementation"
shivamd-gpartner May 15, 2026
76058df
Reapply "revert the pipeline changes"
shivamd-gpartner May 15, 2026
12d0720
improve encoding
shivamd-gpartner May 15, 2026
e235ef3
Revert "improve encoding"
shivamd-gpartner May 19, 2026
20b1c61
Revert "added debug prints"
shivamd-gpartner May 19, 2026
2ce50c3
fix windfows
shivamd-gpartner May 18, 2026
522260b
checkers fix
shivamd-gpartner May 19, 2026
5b12e3f
re2 changes
shivamd-gpartner May 19, 2026
0d5feb2
update cmke
shivamd-gpartner May 19, 2026
aa2989a
fixed clang
shivamd-gpartner May 20, 2026
119456e
udpate comment
shivamd-gpartner May 21, 2026
a5f970d
test_improvement
shivamd-gpartner Jun 3, 2026
4406fb7
removed all references sqlwchar
shivamd-gpartner Jun 4, 2026
30fe794
test
shivamd-gpartner May 28, 2026
f58f85e
checkers fix
shivamd-gpartner Jun 5, 2026
5e1d00f
checkers fix
shivamd-gpartner Jun 5, 2026
bc02d99
test: added test case to verify the behaviour with utf16
sachinpro Aug 12, 2026
caa716d
chore: adding support for utf-8
sachinpro Aug 12, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion ci/cloudbuild/dockerfiles/debian-12-arm64.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -110,10 +110,11 @@ ENV PATH=${CLOUD_SDK_LOCATION}/bin:${PATH}
COPY ./gha/builds/lib/odbc.ini /opt/odbc-driver/odbc.ini
COPY ./gha/builds/lib/odbcinst.ini /opt/odbc-driver/odbcinst.ini
COPY ./gha/builds/lib/lsan.supp /opt/odbc-driver/lsan.supp
COPY ./gha/builds/lib/google.googlebigqueryodbc.ini /opt/odbc-driver/google.googlebigqueryodbc.ini
COPY ./gha/builds/release/odbc.ini /opt/odbc-driver/odbc_template.ini
COPY ./gha/builds/release/odbcinst.ini /opt/odbc-driver/odbcinst_template.ini
COPY ./gha/builds/release/googlebigqueryodbc.ini /opt/odbc-driver/googlebigqueryodbc.ini
COPY ./etc/googlebigqueryodbc_utf16.ini /opt/odbc-driver/googlebigqueryodbc_utf16.ini
COPY ./etc/googlebigqueryodbc_utf8.ini /opt/odbc-driver/googlebigqueryodbc_utf8.ini

# glibc 2.17 or later
RUN echo 'Installing glibc...'
Expand Down
3 changes: 2 additions & 1 deletion ci/cloudbuild/dockerfiles/ubuntu-20.04-release.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,8 @@ COPY ./etc/roots.pem /opt/odbc-driver/roots.pem
COPY ./gha/builds/lib/odbc.ini /opt/odbc-driver/odbc.ini
COPY ./gha/builds/lib/odbcinst.ini /opt/odbc-driver/odbcinst.ini
COPY ./gha/builds/lib/lsan.supp /opt/odbc-driver/lsan.supp
COPY ./gha/builds/lib/google.googlebigqueryodbc.ini /opt/odbc-driver/google.googlebigqueryodbc.ini
COPY ./gha/builds/release/odbc.ini /opt/odbc-driver/odbc_template.ini
COPY ./gha/builds/release/odbcinst.ini /opt/odbc-driver/odbcinst_template.ini
COPY ./gha/builds/release/googlebigqueryodbc.ini /opt/odbc-driver/googlebigqueryodbc.ini
COPY ./etc/googlebigqueryodbc_utf16.ini /opt/odbc-driver/googlebigqueryodbc_utf16.ini
COPY ./etc/googlebigqueryodbc_utf8.ini /opt/odbc-driver/googlebigqueryodbc_utf8.ini
3 changes: 2 additions & 1 deletion ci/cloudbuild/dockerfiles/ubuntu-22.04-full.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,11 @@ COPY ./etc/vcpkg-version.txt /tmp/vcpkg-version.txt
COPY ./gha/builds/lib/odbc.ini /opt/odbc-driver/odbc.ini
COPY ./gha/builds/lib/odbcinst.ini /opt/odbc-driver/odbcinst.ini
COPY ./gha/builds/lib/lsan.supp /opt/odbc-driver/lsan.supp
COPY ./gha/builds/lib/google.googlebigqueryodbc.ini /opt/odbc-driver/google.googlebigqueryodbc.ini
COPY ./gha/builds/release/odbc.ini /opt/odbc-driver/odbc_template.ini
COPY ./gha/builds/release/odbcinst.ini /opt/odbc-driver/odbcinst_template.ini
COPY ./gha/builds/release/googlebigqueryodbc.ini /opt/odbc-driver/googlebigqueryodbc.ini
COPY ./etc/googlebigqueryodbc_utf16.ini /opt/odbc-driver/googlebigqueryodbc_utf16.ini
COPY ./etc/googlebigqueryodbc_utf8.ini /opt/odbc-driver/googlebigqueryodbc_utf8.ini

# glibc 2.17 or later
RUN echo 'Installing glibc...'
Expand Down
3 changes: 2 additions & 1 deletion ci/cloudbuild/dockerfiles/ubuntu-22.04-install.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -133,10 +133,11 @@ COPY ./etc/roots.pem /opt/odbc-driver/roots.pem
COPY ./gha/builds/lib/odbc.ini /opt/odbc-driver/odbc.ini
COPY ./gha/builds/lib/odbcinst.ini /opt/odbc-driver/odbcinst.ini
COPY ./gha/builds/lib/lsan.supp /opt/odbc-driver/lsan.supp
COPY ./gha/builds/lib/google.googlebigqueryodbc.ini /opt/odbc-driver/google.googlebigqueryodbc.ini
COPY ./gha/builds/release/odbc.ini /opt/odbc-driver/odbc_template.ini
COPY ./gha/builds/release/odbcinst.ini /opt/odbc-driver/odbcinst_template.ini
COPY ./gha/builds/release/googlebigqueryodbc.ini /opt/odbc-driver/googlebigqueryodbc.ini
COPY ./etc/googlebigqueryodbc_utf16.ini /opt/odbc-driver/googlebigqueryodbc_utf16.ini
COPY ./etc/googlebigqueryodbc_utf8.ini /opt/odbc-driver/googlebigqueryodbc_utf8.ini

# glibc 2.17 or later
RUN echo 'Installing glibc...'
Expand Down
4 changes: 3 additions & 1 deletion ci/dependencies/driver-manager-setup-google-driver.sh
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@ export LD_LIBRARY_PATH=${LD_LIBRARY_PATH:-}:/usr/local/lib/
export ODBCSYSINI=/opt/odbc-driver
export ODBCINI=/opt/odbc-driver/odbc.ini
export CPP_BIGQUERY_ODBC_TEST_SERVICE_ACCOUNT_AUTH_KEY=/opt/odbc-driver/connection/key.json
export GOOGLEBIGQUERYODBCINI=/opt/odbc-driver/google.googlebigqueryodbc.ini
export GOOGLEBIGQUERYODBCINI=/opt/odbc-driver/googlebigqueryodbc.ini
export GOOGLEBIGQUERYODBCINI_UTF16=/opt/odbc-driver/googlebigqueryodbc_utf16.ini
export GOOGLEBIGQUERYODBCINI_UTF8=/opt/odbc-driver/googlebigqueryodbc_utf8.ini
cd "$CPP_GOOGLE_BIGQUERY_ODBC_DRIVER_MANAGER_SETUP_CURR_DIR"

echo '**** ODBC Driver installation END****'
13 changes: 13 additions & 0 deletions ci/etc/googlebigqueryodbc.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[Driver]
LogLevel=0
LogPath=
# WcharEncoding sets the wire encoding of SQLWCHAR buffers on Linux/macOS
# when the driver is built against iODBC headers (sizeof(SQLWCHAR) == 4).
#
# Accepted values:
# UTF-8 - 1-byte UTF-8 per character
# UTF-16LE - 2-byte UTF-16LE per code unit
# UTF-32LE - 4-byte UTF-32LE per code unit
# (empty) - use sizeof(SQLWCHAR) as-is (default)
#
WcharEncoding=
13 changes: 13 additions & 0 deletions ci/etc/googlebigqueryodbc_utf16.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[Driver]
LogLevel=0
LogPath=
# WcharEncoding sets the wire encoding of SQLWCHAR buffers on Linux/macOS
# when the driver is built against iODBC headers (sizeof(SQLWCHAR) == 4).
#
# Accepted values:
# UTF-8 - 1-byte UTF-8 per character
# UTF-16LE - 2-byte UTF-16LE per code unit
# UTF-32LE - 4-byte UTF-32LE per code unit
# (empty) - use sizeof(SQLWCHAR) as-is (default)
#
WcharEncoding=UTF-16LE
13 changes: 13 additions & 0 deletions ci/etc/googlebigqueryodbc_utf8.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[Driver]
LogLevel=0
LogPath=
# WcharEncoding sets the wire encoding of SQLWCHAR buffers on Linux/macOS
# when the driver is built against iODBC headers (sizeof(SQLWCHAR) == 4).
#
# Accepted values:
# UTF-8 - 1-byte UTF-8 per character
# UTF-16LE - 2-byte UTF-16LE per code unit
# UTF-32LE - 4-byte UTF-32LE per code unit
# (empty) - use sizeof(SQLWCHAR) as-is (default)
#
WcharEncoding=UTF-8
3 changes: 0 additions & 3 deletions ci/gha/builds/lib/google.googlebigqueryodbc.ini

This file was deleted.

13 changes: 13 additions & 0 deletions ci/gha/builds/lib/googlebigqueryodbc.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[Driver]
LogLevel=0
LogPath=
# WcharEncoding sets the wire encoding of SQLWCHAR buffers on Linux/macOS
# when the driver is built against iODBC headers (sizeof(SQLWCHAR) == 4).
#
# Accepted values:
# UTF-8 - 1-byte UTF-8 per character
# UTF-16LE - 2-byte UTF-16LE per code unit
# UTF-32LE - 4-byte UTF-32LE per code unit
# (empty) - use sizeof(SQLWCHAR) as-is (default)
#
WcharEncoding=
8 changes: 6 additions & 2 deletions ci/gha/builds/macos-cmake.sh
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,16 @@ mv /Users/runner/work/connection/external_account_auth_keys.json.tmp /Users/runn

cp ci/gha/builds/lib/odbc_osx.ini /Users/runner/work/connection/odbc-driver/odbc.ini
cp ci/gha/builds/lib/odbcinst_osx.ini /Users/runner/work/connection/odbc-driver/odbcinst.ini
cp ci/gha/builds/lib/google.googlebigqueryodbc.ini /Users/runner/work/connection/google.googlebigqueryodbc.ini
cp ci/gha/builds/lib/googlebigqueryodbc.ini /Users/runner/work/connection/googlebigqueryodbc.ini
cp ci/etc/googlebigqueryodbc_utf16.ini /Users/runner/work/connection/googlebigqueryodbc_utf16.ini
cp ci/etc/googlebigqueryodbc_utf8.ini /Users/runner/work/connection/googlebigqueryodbc_utf8.ini
# Copy the roots.pem file to the .so directory to run test cases.
cp ci/etc/roots.pem /Users/runner/work/cpp-bigquery-odbc/cpp-bigquery-odbc/cmake-out/google/cloud/odbc/roots.pem
export ODBCINI=/Users/runner/work/connection/odbc-driver/odbc.ini
export ODBCINSTINI=/Users/runner/work/connection/odbc-driver/odbcinst.ini
export GOOGLEBIGQUERYODBCINI=/Users/runner/work/connection/google.googlebigqueryodbc.ini
export GOOGLEBIGQUERYODBCINI=/Users/runner/work/connection/googlebigqueryodbc.ini
export GOOGLEBIGQUERYODBCINI_UTF16=/Users/runner/work/connection/googlebigqueryodbc_utf16.ini
export GOOGLEBIGQUERYODBCINI_UTF8=/Users/runner/work/connection/googlebigqueryodbc_utf8.ini
export ODBC_TESTS_DSN="SampleDSNGoogleDriver"
export CPP_BIGQUERY_ODBC_TEST_SERVICE_ACCOUNT_AUTH_KEY=/Users/runner/work/connection/key.json
export CPP_BIGQUERY_ODBC_TEST_EXTERNAL_ACCOUNT_AUTH_KEY=/Users/runner/work/connection/external_account_auth_keys.json
Expand Down
11 changes: 11 additions & 0 deletions ci/gha/builds/release/googlebigqueryodbc.ini
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,14 @@ LogFileSize=2000

# MaxThreads(Optional): Maximum threads the driver will spawn for catalog APIs
MaxThreads=8

# WcharEncoding sets the wire encoding of SQLWCHAR buffers on Linux/macOS
# when the driver is built against iODBC headers (sizeof(SQLWCHAR) == 4).
#
# Accepted values:
# UTF-8 - 1-byte UTF-8 per character
# UTF-16LE - 2-byte UTF-16LE per code unit
# UTF-32LE - 4-byte UTF-32LE per code unit
# (empty) - use sizeof(SQLWCHAR) as-is (default)
#
WcharEncoding=
9 changes: 9 additions & 0 deletions google/cloud/odbc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,15 @@ else ()
find_package(google_cloud_cpp_serviceusage REQUIRED)
endif ()

find_package(re2 CONFIG QUIET)
if (NOT TARGET re2::re2)
if (TARGET re2)
add_library(re2::re2 ALIAS re2)
else ()
find_package(re2 REQUIRED)
endif ()
endif ()

# Restore the original BUILD_SHARED_LIBS value
set(BUILD_SHARED_LIBS ${ORIGINAL_BUILD_SHARED_LIBS})

Expand Down
123 changes: 50 additions & 73 deletions google/cloud/odbc/bq_driver/internal/data_translation.cc
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ odbc_internal::StatusRecord ConvertFromNumericDSValue(DSValue const& src_dsval,
"DSValueToWchar Conversion Failed"};
break;
}
SQLLEN wchar_capacity = dest_data.buflen / sizeof(SQLWCHAR);
SQLLEN wchar_capacity = dest_data.buflen / WireWcharSize();
auto src_len = static_cast<SQLINTEGER>(wstr->length());
SQLINTEGER required_chars = src_len + 1;
WStrToOutputBufferResponse(wstr.GetValue(), dest_data.buf, wchar_capacity,
Expand Down Expand Up @@ -326,7 +326,7 @@ odbc_internal::StatusRecord ConvertFromStringDSValue(DSValue const& src_dsval,
}

auto src_len = static_cast<SQLINTEGER>(wide_str.length());
SQLLEN wchar_capacity = dest_data.buflen / sizeof(SQLWCHAR);
SQLLEN wchar_capacity = dest_data.buflen / WireWcharSize();
SQLINTEGER required_chars = src_len + 1;
return WStrToOutputBufferResponse(wide_str, dest_data.buf, wchar_capacity,
src_len, required_chars,
Expand Down Expand Up @@ -907,7 +907,7 @@ odbc_internal::StatusRecord ConvertFromTimeDSValue(DSValue const& src_dsval,
"DSValueToWchar Conversion Failed"};
break;
}
SQLLEN wchar_capacity = buffer_length / sizeof(SQLWCHAR);
SQLLEN wchar_capacity = buffer_length / WireWcharSize();
SQLLEN required_chars = static_cast<SQLLEN>(wstr->length()) + 1;
return WStrToOutputBufferResponse(
wstr.GetValue(), dest_buf, wchar_capacity, k_time_src_len,
Expand Down Expand Up @@ -1007,30 +1007,22 @@ odbc_internal::StatusRecord ConvertFromTimestampDSValue(
"DSValueToWchar Conversion Failed"};
break;
}
std::wstring wstr_val = wstr.GetValue();
if (!wstr_val.empty() && wstr_val.back() == L'\0') {
wstr_val.pop_back();
}
std::vector<SQLWCHAR> wstr_data(wstr_val.begin(), wstr_val.end());
wstr_data.emplace_back(L'\0');

auto* dest = reinterpret_cast<SQLWCHAR*>(dest_buf);
SQLLEN wchar_capacity = buffer_length / sizeof(SQLWCHAR);
size_t const wire_sz = WireWcharSize();
SQLLEN wchar_capacity = buffer_length / static_cast<SQLLEN>(wire_sz);
if (wchar_capacity > k_timestamp_src_len) {
if (res_len) {
*res_len = k_timestamp_src_len * sizeof(SQLWCHAR);
*res_len = static_cast<SQLLEN>(wstr.GetValue().size() * wire_sz);
}
std::memcpy(dest, wstr_data.data(),
(k_timestamp_src_len) * sizeof(SQLWCHAR));
dest[k_timestamp_src_len] = L'\0';
WriteWideToWireBuffer(wstr.GetValue(), dest_buf, wstr.GetValue().size(),
/*null_terminate=*/true);
} else if (20 <= wchar_capacity &&
wchar_capacity <= k_timestamp_src_len) {
if (res_len) {
*res_len = wchar_capacity * sizeof(SQLWCHAR);
*res_len = wchar_capacity * static_cast<SQLLEN>(wire_sz);
}
std::memcpy(dest, wstr_data.data(),
(wchar_capacity) * sizeof(SQLWCHAR));
dest[wchar_capacity - 1] = L'\0';
WriteWideToWireBuffer(wstr.GetValue(), dest_buf,
static_cast<size_t>(wchar_capacity - 1),
/*null_terminate=*/true);
LOG(WARNING)
<< "ConvertFromTimestampDSValue:: Data truncated for SQL_C_WCHAR.";
status_record = StatusRecord{SQLStates::k_01004(), "Data truncated"};
Expand Down Expand Up @@ -1189,29 +1181,21 @@ odbc_internal::StatusRecord ConvertFromDatetimeDSValue(DSValue const& src_dsval,
"DSValueToWchar Conversion Failed"};
break;
}
std::wstring wstr_val = wstr.GetValue();
if (!wstr_val.empty() && wstr_val.back() == L'\0') {
wstr_val.pop_back();
}
std::vector<SQLWCHAR> wstr_data(wstr_val.begin(), wstr_val.end());
wstr_data.emplace_back(L'\0');

auto* dest = reinterpret_cast<SQLWCHAR*>(dest_buf);
SQLLEN wchar_capacity = buffer_length / sizeof(SQLWCHAR);
size_t const wire_sz = WireWcharSize();
SQLLEN wchar_capacity = buffer_length / static_cast<SQLLEN>(wire_sz);
if (wchar_capacity > k_datetime_src_len) {
if (res_len) {
*res_len = k_datetime_src_len * sizeof(SQLWCHAR);
*res_len = static_cast<SQLLEN>(wstr.GetValue().size() * wire_sz);
}
std::memcpy(dest, wstr_data.data(),
(k_datetime_src_len) * sizeof(SQLWCHAR));
dest[k_datetime_src_len] = L'\0';
WriteWideToWireBuffer(wstr.GetValue(), dest_buf, wstr.GetValue().size(),
/*null_terminate=*/true);
} else if (20 <= wchar_capacity && wchar_capacity <= k_datetime_src_len) {
if (res_len) {
*res_len = wchar_capacity * sizeof(SQLWCHAR);
*res_len = wchar_capacity * static_cast<SQLLEN>(wire_sz);
}
std::memcpy(dest, wstr_data.data(),
(wchar_capacity) * sizeof(SQLWCHAR));
dest[wchar_capacity - 1] = L'\0';
WriteWideToWireBuffer(wstr.GetValue(), dest_buf,
static_cast<size_t>(wchar_capacity - 1),
/*null_terminate=*/true);
LOG(WARNING)
<< "ConvertFromDatetimeDSValue:: Data truncated for SQL_C_WCHAR.";
status_record = StatusRecord{SQLStates::k_01004(), "Data truncated"};
Expand Down Expand Up @@ -1398,7 +1382,7 @@ odbc_internal::StatusRecord ConvertFromDateDSValue(DSValue const& src_dsval,
return StatusRecord{SQLStates::k_HY000(),
"DSValueToWchar Conversion Failed"};
}
SQLLEN wchar_capacity = buffer_length / sizeof(SQLWCHAR);
SQLLEN wchar_capacity = buffer_length / WireWcharSize();
auto src_len = static_cast<SQLINTEGER>(wstr->length());
SQLINTEGER required_chars = src_len + 1;
return WStrToOutputBufferResponse(
Expand Down Expand Up @@ -1434,7 +1418,7 @@ StatusRecord ConvertStringToJsonOutputBuffer(std::string const& src_str,
return StatusRecord{SQLStates::k_HY000(),
"Conversion to UTF-16 failed"};
}
SQLLEN wchar_capacity = buffer_length / sizeof(SQLWCHAR);
SQLLEN wchar_capacity = buffer_length / WireWcharSize();
auto src_len = static_cast<SQLINTEGER>(wide_string->length());
SQLINTEGER required_chars = src_len + 1;
return WStrToOutputBufferResponse(wide_string.GetValue(), dest_buf,
Expand Down Expand Up @@ -1498,15 +1482,11 @@ StatusRecord ConvertFromArrayDSValue(DSValue const& src_dsval,
if (!wide_string.Ok()) {
return StatusRecord{SQLStates::k_HY000(), "Conversion Failed"};
}
std::wstring wide_val = wide_string.GetValue();
if (!wide_val.empty() && wide_val.back() == L'\0') {
wide_val.pop_back();
}
SQLLEN wchar_capacity = dest_data.buflen / sizeof(SQLWCHAR);
auto src_len = static_cast<SQLINTEGER>(wide_val.length());
SQLLEN wchar_capacity = dest_data.buflen / WireWcharSize();
auto src_len = static_cast<SQLINTEGER>(wide_string->length());
SQLINTEGER required_chars = src_len + 1;
return WStrToOutputBufferResponse(
wide_val, dest_data.buf, wchar_capacity, src_len, required_chars,
*wide_string, dest_data.buf, wchar_capacity, src_len, required_chars,
reinterpret_cast<SQLLEN*>(dest_data.result_len));
}
case SQL_C_BINARY: {
Expand Down Expand Up @@ -1621,7 +1601,7 @@ odbc_internal::StatusRecord ConvertFromIntervalDSValue(DSValue const& src_dsval,
StatusRecord{SQLStates::k_HY000(), wstr.GetStatusRecord().message};
break;
}
SQLLEN wchar_capacity = buffer_length / sizeof(SQLWCHAR);
SQLLEN wchar_capacity = buffer_length / WireWcharSize();
auto interval_char_length =
static_cast<SQLINTEGER>(wstr.GetValue().length());
return WStrIntervalBufferResponse(
Expand Down Expand Up @@ -1907,7 +1887,7 @@ StatusRecord ConvertFromGeographyDSValue(DSValue const& src_dsval,
}
std::memset(dest_data.buf, 0, buffer_length);
std::wstring const& wide_str = wstr.GetValue();
SQLLEN wchar_capacity = buffer_length / sizeof(SQLWCHAR);
SQLLEN wchar_capacity = buffer_length / WireWcharSize();
SQLLEN src_len = static_cast<SQLLEN>(wide_str.length());
SQLLEN required_chars = src_len + 1;
status_record = WStrToOutputBufferResponse(
Expand Down Expand Up @@ -2054,38 +2034,35 @@ StatusRecord ConvertBytesToWChar(DSValue const& conn_val,
"UTF-8 to UTF-16 conversion failed."};
}

std::wstring utf16_value = utf16_str.GetValue();
if (!utf16_value.empty() && utf16_value.back() == L'\0') {
utf16_value.pop_back();
}
size_t const required_size = utf16_value.length() * sizeof(SQLWCHAR);
std::wstring const& utf16_value = utf16_str.GetValue();

auto* buffer = reinterpret_cast<SQLWCHAR*>(dest_data.buf);

// Handle truncation if buffer is insufficient
if (dest_data.buflen < required_size) {
size_t num_chars_to_copy = (dest_data.buflen / sizeof(SQLWCHAR)) - 1;
std::memcpy(buffer, utf16_value.data(),
num_chars_to_copy * sizeof(SQLWCHAR));
buffer[num_chars_to_copy] = L'\0';
// Narrow wchar_t -> wire encoding directly into the caller's buffer.
// No intermediate vector; WriteWideToWireBuffer is a memcpy when the wire
// SQLWCHAR width matches sizeof(wchar_t) and a per-element narrowing loop
// only on the iODBC-built / unixODBC-loaded path.
size_t const wire_sz = WireWcharSize();
size_t const src_chars = utf16_value.size();
size_t const required_size = src_chars * wire_sz;

if (static_cast<size_t>(dest_data.buflen) < required_size) {
size_t num_chars_to_copy = dest_data.buflen / wire_sz;
if (num_chars_to_copy > 0) {
num_chars_to_copy--; // leave one slot for the null terminator
WriteWideToWireBuffer(utf16_value, dest_data.buf, num_chars_to_copy,
/*null_terminate=*/true);
}
if (dest_data.result_len) {
*dest_data.result_len = dest_data.buflen;
*dest_data.result_len = required_size;
}
LOG(WARNING) << "ConvertBytesToWChar:: String data, right truncated.";
return StatusRecord{SQLStates::k_01004(), "String data, right truncated"};
}
for (size_t i = 0; i < utf16_str.GetValue().size(); ++i) {
buffer[i] = static_cast<SQLWCHAR>(utf16_str.GetValue()[i]);
}
size_t buffer_chars = dest_data.buflen / sizeof(SQLWCHAR);
if (utf16_str.GetValue().size() < buffer_chars) {
buffer[utf16_str.GetValue().size()] = L'\0';
}

// Set output length
bool const can_null_terminate =
static_cast<size_t>(dest_data.buflen) >= required_size + wire_sz;
WriteWideToWireBuffer(utf16_value, dest_data.buf, src_chars,
can_null_terminate);
if (dest_data.result_len) {
*dest_data.result_len = utf16_str.GetValue().size() * sizeof(SQLWCHAR);
*dest_data.result_len = required_size;
}
return status_record;
}
Expand Down Expand Up @@ -2253,7 +2230,7 @@ StatusRecord ConvertFromRangeDSValue(DSValue const& src_dsval,
return StatusRecord{SQLStates::k_HY000(),
"Conversion to SQL_C_WCHAR failed."};
}
SQLLEN wchar_capacity = buffer_length / sizeof(SQLWCHAR);
SQLLEN wchar_capacity = buffer_length / WireWcharSize();
SQLLEN src_len = static_cast<SQLLEN>(wstr->length());
SQLLEN required_chars = src_len + 1;
return WStrToOutputBufferResponse(
Expand Down
Loading
Loading