Skip to content

Commit

Permalink
Merge pull request #280 from traceon/unicode-reuse-converter
Browse files Browse the repository at this point in the history
Store and pass stateful converters in conversion contexts
  • Loading branch information
Enmk authored Mar 20, 2020
2 parents 19acec5 + e99250c commit 5e15083
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 111 deletions.
22 changes: 2 additions & 20 deletions driver/result_set.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,24 +99,6 @@ void ColumnInfo::updateTypeInfo() {
}
}

SQLRETURN Field::extract(BindingInfo & binding_info) const {
return std::visit([&binding_info] (auto & value) {
if constexpr (std::is_same_v<DataSourceType<DataSourceTypeId::Nothing>, std::decay_t<decltype(value)>>) {
return fillOutputNULL(binding_info.value, binding_info.value_max_size, binding_info.indicator);
}
else {
return writeDataFrom(value, binding_info);
}
}, data);
}

SQLRETURN Row::extractField(std::size_t column_idx, BindingInfo & binding_info) const {
if (column_idx >= fields.size())
throw SqlException("Invalid descriptor index", "07009");

return fields[column_idx].extract(binding_info);
}

ResultSet::ResultSet(AmortizedIStreamReader & str, std::unique_ptr<ResultMutator> && mutator)
: stream(str)
, result_mutator(std::move(mutator))
Expand Down Expand Up @@ -202,11 +184,11 @@ std::size_t ResultSet::getAffectedRowCount() const {
return affected_row_count;
}

SQLRETURN ResultSet::extractField(std::size_t row_idx, std::size_t column_idx, BindingInfo & binding_info) const {
SQLRETURN ResultSet::extractField(std::size_t row_idx, std::size_t column_idx, BindingInfo & binding_info) {
if (row_idx >= row_set.size())
throw SqlException("Invalid cursor position", "HY109");

return row_set[row_idx].extractField(column_idx, binding_info);
return row_set[row_idx].extractField(column_idx, binding_info, conversion_context);
}

void ResultSet::tryPrefetchRows(std::size_t size) {
Expand Down
29 changes: 26 additions & 3 deletions driver/result_set.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,15 +62,17 @@ class Field {
WireTypeDateTimeAsInt
>;

SQLRETURN extract(BindingInfo & binding_info) const;
template <typename ConversionContext>
SQLRETURN extract(BindingInfo & binding_info, ConversionContext && context) const;

public:
DataType data = DataSourceType<DataSourceTypeId::Nothing>{};
};

class Row {
public:
SQLRETURN extractField(std::size_t column_idx, BindingInfo & binding_info) const;
template <typename ConversionContext>
SQLRETURN extractField(std::size_t column_idx, BindingInfo & binding_info, ConversionContext && context) const;

public:
std::vector<Field> fields;
Expand Down Expand Up @@ -102,7 +104,7 @@ class ResultSet {
std::size_t getAffectedRowCount() const;

// row_idx - row index within the row set.
SQLRETURN extractField(std::size_t row_idx, std::size_t column_idx, BindingInfo & binding_info) const;
SQLRETURN extractField(std::size_t row_idx, std::size_t column_idx, BindingInfo & binding_info);

protected:
void tryPrefetchRows(std::size_t size);
Expand All @@ -113,6 +115,7 @@ class ResultSet {
protected:
AmortizedIStreamReader & stream;
std::unique_ptr<ResultMutator> result_mutator;
DefaultConversionContext conversion_context;
std::vector<ColumnInfo> columns_info;
std::deque<Row> row_set;
std::size_t row_set_position = 0; // 1-based. 1 means the first row of the row set is the first row of the entire result set.
Expand Down Expand Up @@ -145,3 +148,23 @@ class ResultReader {
};

std::unique_ptr<ResultReader> make_result_reader(const std::string & format, std::istream & raw_stream, std::unique_ptr<ResultMutator> && mutator);

template <typename ConversionContext>
SQLRETURN Field::extract(BindingInfo & binding_info, ConversionContext && context) const {
return std::visit([&binding_info, &context] (auto & value) {
if constexpr (std::is_same_v<DataSourceType<DataSourceTypeId::Nothing>, std::decay_t<decltype(value)>>) {
return fillOutputNULL(binding_info.value, binding_info.value_max_size, binding_info.indicator);
}
else {
return writeDataFrom(value, binding_info, std::forward<ConversionContext>(context));
}
}, data);
}

template <typename ConversionContext>
SQLRETURN Row::extractField(std::size_t column_idx, BindingInfo & binding_info, ConversionContext && context) const {
if (column_idx >= fields.size())
throw SqlException("Invalid descriptor index", "07009");

return fields[column_idx].extract(binding_info, std::forward<ConversionContext>(context));
}
45 changes: 26 additions & 19 deletions driver/utils/type_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,8 @@ inline T fromString(const std::string & s) {
return result;
}

using DefaultConversionContext = UnicodeConversionContext;

// Directly write raw bytes to the buffer, respecting its size.
// All lengths are in bytes. If 'out_value_max_length == 0',
// assume 'out_value' is able to hold the entire 'in_value'.
Expand Down Expand Up @@ -207,15 +209,16 @@ inline SQLRETURN fillOutputBuffer(

// Change encoding, when appropriate, and write the result to the buffer.
// Extra string copy happens here for wide char strings, and strings that require encoding change.
template <typename CharType, typename LengthType1, typename LengthType2>
template <typename CharType, typename LengthType1, typename LengthType2, typename ConversionContext>
inline SQLRETURN fillOutputString(
const std::string & in_value,
void * out_value,
LengthType1 out_value_max_length,
LengthType2 * out_value_length,
bool in_length_in_bytes,
bool out_length_in_bytes,
bool ensure_nts
bool ensure_nts,
ConversionContext && context
) {
if (out_value) {
if (out_value_max_length <= 0)
Expand All @@ -225,7 +228,7 @@ inline SQLRETURN fillOutputString(
throw SqlException("Invalid string or buffer length", "HY090");
}

auto && converted = fromUTF8<CharType>(in_value);
auto && converted = fromUTF8<CharType>(in_value, context);

const auto converted_length_in_symbols = converted.size();
const auto converted_length_in_bytes = converted_length_in_symbols * sizeof(CharType);
Expand Down Expand Up @@ -261,13 +264,14 @@ inline SQLRETURN fillOutputString(
return SQL_SUCCESS;
}

template <typename CharType, typename LengthType1, typename LengthType2>
template <typename CharType, typename LengthType1, typename LengthType2, typename ConversionContext = DefaultConversionContext>
inline SQLRETURN fillOutputString(
const std::string & in_value,
void * out_value,
LengthType1 out_value_max_length,
LengthType2 * out_value_length,
bool length_in_bytes
bool length_in_bytes,
ConversionContext && context = ConversionContext{}
) {
return fillOutputString<CharType>(
in_value,
Expand All @@ -276,7 +280,8 @@ inline SQLRETURN fillOutputString(
out_value_length,
length_in_bytes,
length_in_bytes,
true
true,
std::forward<ConversionContext>(context)
);
}

Expand Down Expand Up @@ -1839,18 +1844,19 @@ namespace value_manip {

template <typename SourceType>
struct from_value {
static inline SQLRETURN convert(const SourceType & src, BindingInfo & dest) {
template <typename ConversionContext>
static inline SQLRETURN convert(const SourceType & src, BindingInfo & dest, ConversionContext && context) {
if constexpr (std::is_same_v<SourceType, std::string>) {
return fillOutputString<SQLCHAR>(src, dest.value, dest.value_max_size, dest.value_size, true);
return fillOutputString<SQLCHAR>(src, dest.value, dest.value_max_size, dest.value_size, true, std::forward<ConversionContext>(context));
}
else if constexpr (is_string_data_source_type_v<SourceType>) {
return fillOutputString<SQLCHAR>(src.value, dest.value, dest.value_max_size, dest.value_size, true);
return fillOutputString<SQLCHAR>(src.value, dest.value, dest.value_max_size, dest.value_size, true, std::forward<ConversionContext>(context));
}
else {
std::string dest_obj;
to_null(dest_obj);
::value_manip::from_value<SourceType>::template to_value<std::string>::convert(src, dest_obj);
return fillOutputString<SQLCHAR>(dest_obj, dest.value, dest.value_max_size, dest.value_size, true);
return fillOutputString<SQLCHAR>(dest_obj, dest.value, dest.value_max_size, dest.value_size, true, std::forward<ConversionContext>(context));
}
}
};
Expand All @@ -1862,18 +1868,19 @@ namespace value_manip {

template <typename SourceType>
struct from_value {
static inline SQLRETURN convert(const SourceType & src, BindingInfo & dest) {
template <typename ConversionContext>
static inline SQLRETURN convert(const SourceType & src, BindingInfo & dest, ConversionContext && context) {
if constexpr (std::is_same_v<SourceType, std::string>) {
return fillOutputString<SQLWCHAR>(src, dest.value, dest.value_max_size, dest.value_size, true);
return fillOutputString<SQLWCHAR>(src, dest.value, dest.value_max_size, dest.value_size, true, std::forward<ConversionContext>(context));
}
else if constexpr (is_string_data_source_type_v<SourceType>) {
return fillOutputString<SQLWCHAR>(src.value, dest.value, dest.value_max_size, dest.value_size, true);
return fillOutputString<SQLWCHAR>(src.value, dest.value, dest.value_max_size, dest.value_size, true, std::forward<ConversionContext>(context));
}
else {
std::string dest_obj;
to_null(dest_obj);
::value_manip::from_value<SourceType>::template to_value<std::string>::convert(src, dest_obj);
return fillOutputString<SQLWCHAR>(dest_obj, dest.value, dest.value_max_size, dest.value_size, true);
return fillOutputString<SQLWCHAR>(dest_obj, dest.value, dest.value_max_size, dest.value_size, true, std::forward<ConversionContext>(context));
}
}
};
Expand Down Expand Up @@ -2179,11 +2186,11 @@ inline auto readReadyDataTo(const BindingInfo & src, T & dest) {
}
}

template <typename T>
inline auto writeDataFrom(const T & src, BindingInfo & dest) {
template <typename T, typename ConversionContext>
inline auto writeDataFrom(const T & src, BindingInfo & dest, ConversionContext && context) {
switch (dest.c_type) {
case SQL_C_CHAR: return value_manip::to_buffer< SQLCHAR * >::template from_value< T >::convert(src, dest);
case SQL_C_WCHAR: return value_manip::to_buffer< SQLWCHAR * >::template from_value< T >::convert(src, dest);
case SQL_C_CHAR: return value_manip::to_buffer< SQLCHAR * >::template from_value< T >::convert(src, dest, std::forward<ConversionContext>(context));
case SQL_C_WCHAR: return value_manip::to_buffer< SQLWCHAR * >::template from_value< T >::convert(src, dest, std::forward<ConversionContext>(context));
case SQL_C_BIT: return value_manip::to_buffer< SQLCHAR >::template from_value< T >::convert(src, dest);
case SQL_C_TINYINT: return value_manip::to_buffer< SQLSCHAR >::template from_value< T >::convert(src, dest);
case SQL_C_STINYINT: return value_manip::to_buffer< SQLSCHAR >::template from_value< T >::convert(src, dest);
Expand All @@ -2198,7 +2205,7 @@ inline auto writeDataFrom(const T & src, BindingInfo & dest) {
case SQL_C_UBIGINT: return value_manip::to_buffer< SQLUBIGINT >::template from_value< T >::convert(src, dest);
case SQL_C_FLOAT: return value_manip::to_buffer< SQLREAL >::template from_value< T >::convert(src, dest);
case SQL_C_DOUBLE: return value_manip::to_buffer< SQLDOUBLE >::template from_value< T >::convert(src, dest);
case SQL_C_BINARY: return value_manip::to_buffer< SQLCHAR * >::template from_value< T >::convert(src, dest);
case SQL_C_BINARY: return value_manip::to_buffer< SQLCHAR * >::template from_value< T >::convert(src, dest, std::forward<ConversionContext>(context));
case SQL_C_GUID: return value_manip::to_buffer< SQLGUID >::template from_value< T >::convert(src, dest);

// case SQL_C_BOOKMARK: return value_manip::to_buffer< BOOKMARK >::template from_value< T >::convert(src, dest);
Expand Down
Loading

0 comments on commit 5e15083

Please sign in to comment.