Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Delay conversions during data fetching from the data source #270

Merged
merged 3 commits into from
Mar 2, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
13 changes: 12 additions & 1 deletion driver/format/ODBCDriver2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,14 @@ void ODBCDriver2ResultSet::readValue(Field & dest, ColumnInfo & column_info) {
if (column_info.display_size_so_far < value.size())
column_info.display_size_so_far = value.size();

switch (column_info.type_without_parameters_id) {
constexpr bool convert_on_fetch_conservatively = true;

if (convert_on_fetch_conservatively) switch (column_info.type_without_parameters_id) {
case DataSourceTypeId::FixedString: readValueAs<DataSourceType< DataSourceTypeId::FixedString >>(value, dest, column_info); break;
case DataSourceTypeId::String: readValueAs<DataSourceType< DataSourceTypeId::String >>(value, dest, column_info); break;
default: readValueAs<WireTypeAnyAsString >(value, dest, column_info); break;
}
else switch (column_info.type_without_parameters_id) {
case DataSourceTypeId::Date: readValueAs<DataSourceType< DataSourceTypeId::Date >>(value, dest, column_info); break;
case DataSourceTypeId::DateTime: readValueAs<DataSourceType< DataSourceTypeId::DateTime >>(value, dest, column_info); break;
case DataSourceTypeId::Decimal: readValueAs<DataSourceType< DataSourceTypeId::Decimal >>(value, dest, column_info); break;
Expand Down Expand Up @@ -144,6 +151,10 @@ void ODBCDriver2ResultSet::readValue(Field & dest, ColumnInfo & column_info) {
string_pool.put(std::move(value));
}

void ODBCDriver2ResultSet::readValue(std::string & src, WireTypeAnyAsString & dest, ColumnInfo & column_info) {
dest.value = std::move(src);
}

void ODBCDriver2ResultSet::readValue(std::string & src, DataSourceType<DataSourceTypeId::Date> & dest, ColumnInfo & column_info) {
return value_manip::from_value<std::string>::template to_value<DataSourceType<DataSourceTypeId::Date>>::convert(src, dest);
}
Expand Down
2 changes: 2 additions & 0 deletions driver/format/ODBCDriver2.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ class ODBCDriver2ResultSet
dest.data = std::move(value);
}

void readValue(std::string & src, WireTypeAnyAsString & dest, ColumnInfo & column_info);

void readValue(std::string & src, DataSourceType< DataSourceTypeId::Date > & dest, ColumnInfo & column_info);
void readValue(std::string & src, DataSourceType< DataSourceTypeId::DateTime > & dest, ColumnInfo & column_info);
void readValue(std::string & src, DataSourceType< DataSourceTypeId::Decimal > & dest, ColumnInfo & column_info);
Expand Down
43 changes: 21 additions & 22 deletions driver/format/RowBinaryWithNamesAndTypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,14 @@ void RowBinaryWithNamesAndTypesResultSet::readValue(Field & dest, ColumnInfo & c
}
}

constexpr bool convert_on_fetch_conservatively = true;

if (convert_on_fetch_conservatively) switch (column_info.type_without_parameters_id) {
case DataSourceTypeId::Date: return readValueAs<WireTypeDateAsInt >(dest, column_info);
case DataSourceTypeId::DateTime: return readValueAs<WireTypeDateTimeAsInt>(dest, column_info);
default: break; // Continue with the next complete switch...
}

switch (column_info.type_without_parameters_id) {
case DataSourceTypeId::Date: return readValueAs<DataSourceType< DataSourceTypeId::Date >>(dest, column_info);
case DataSourceTypeId::DateTime: return readValueAs<DataSourceType< DataSourceTypeId::DateTime >>(dest, column_info);
Expand All @@ -138,33 +146,24 @@ void RowBinaryWithNamesAndTypesResultSet::readValue(Field & dest, ColumnInfo & c
}
}

void RowBinaryWithNamesAndTypesResultSet::readValue(DataSourceType<DataSourceTypeId::Date> & dest, ColumnInfo & column_info) {
std::uint16_t days_since_epoch = 0;
readPOD(days_since_epoch);
void RowBinaryWithNamesAndTypesResultSet::readValue(WireTypeDateAsInt & dest, ColumnInfo & column_info) {
readPOD(dest.value);
}

std::time_t time = days_since_epoch;
time = time * 24 * 60 * 60; // Now it's seconds since epoch.
const auto & tm = *std::localtime(&time);
void RowBinaryWithNamesAndTypesResultSet::readValue(WireTypeDateTimeAsInt & dest, ColumnInfo & column_info) {
readPOD(dest.value);
}

dest.value.year = 1900 + tm.tm_year;
dest.value.month = 1 + tm.tm_mon;
dest.value.day = tm.tm_mday;
void RowBinaryWithNamesAndTypesResultSet::readValue(DataSourceType<DataSourceTypeId::Date> & dest, ColumnInfo & column_info) {
WireTypeDateAsInt dest_raw;
readValue(dest_raw, column_info);
value_manip::from_value<decltype(dest_raw)>::template to_value<decltype(dest)>::convert(dest_raw, dest);
}

void RowBinaryWithNamesAndTypesResultSet::readValue(DataSourceType<DataSourceTypeId::DateTime> & dest, ColumnInfo & column_info) {
std::uint32_t secs_since_epoch = 0;
readPOD(secs_since_epoch);

std::time_t time = secs_since_epoch;
const auto & tm = *std::localtime(&time);

dest.value.year = 1900 + tm.tm_year;
dest.value.month = 1 + tm.tm_mon;
dest.value.day = tm.tm_mday;
dest.value.hour = tm.tm_hour;
dest.value.minute = tm.tm_min;
dest.value.second = tm.tm_sec;
dest.value.fraction = 0;
WireTypeDateTimeAsInt dest_raw;
readValue(dest_raw, column_info);
value_manip::from_value<decltype(dest_raw)>::template to_value<decltype(dest)>::convert(dest_raw, dest);
}

void RowBinaryWithNamesAndTypesResultSet::readValue(DataSourceType<DataSourceTypeId::Decimal> & dest, ColumnInfo & column_info) {
Expand Down
3 changes: 3 additions & 0 deletions driver/format/RowBinaryWithNamesAndTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ class RowBinaryWithNamesAndTypesResultSet
dest.data = std::move(value);
}

void readValue(WireTypeDateAsInt & dest, ColumnInfo & column_info);
void readValue(WireTypeDateTimeAsInt & dest, ColumnInfo & column_info);

void readValue(DataSourceType< DataSourceTypeId::Date > & dest, ColumnInfo & column_info);
void readValue(DataSourceType< DataSourceTypeId::DateTime > & dest, ColumnInfo & column_info);
void readValue(DataSourceType< DataSourceTypeId::Decimal > & dest, ColumnInfo & column_info);
Expand Down
7 changes: 6 additions & 1 deletion driver/result_set.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,12 @@ class Field {
DataSourceType< DataSourceTypeId::UInt16 >,
DataSourceType< DataSourceTypeId::UInt32 >,
DataSourceType< DataSourceTypeId::UInt64 >,
DataSourceType< DataSourceTypeId::UUID >
DataSourceType< DataSourceTypeId::UUID >,

// In case we approach value conversion conservatively...
WireTypeAnyAsString,
WireTypeDateAsInt,
WireTypeDateTimeAsInt
>;

SQLRETURN extract(BindingInfo & binding_info) const;
Expand Down
11 changes: 6 additions & 5 deletions driver/test/statement_parameters_it.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -604,7 +604,8 @@ TEST_P(ParameterColumnRoundTripDecimalAsStringSymmetric, Execute) {
INSTANTIATE_TEST_SUITE_P(TypeConversion, ParameterColumnRoundTripDecimalAsStringSymmetric,
::testing::Values(

// TODO: do DECIMALs have to not start with dot?
// TODO: add cases with 0 whole part. Currently the unified testing doesn't play well with the
// different wire formats with enabled conservative value conversions.

"0",
"12345",
Expand All @@ -615,11 +616,11 @@ INSTANTIATE_TEST_SUITE_P(TypeConversion, ParameterColumnRoundTripDecimalAsString
"12345.001002003000",
"100000000000000000",
"-100000000000000000",
".000000000000000001",
"-.000000000000000001",
"1.00000000000000001",
"-1.00000000000000001",
"999999999999999999",
"-999999999999999999",
".999999999999999999",
"-.999999999999999999"
"1.99999999999999999",
"-1.99999999999999999"
)
);
97 changes: 96 additions & 1 deletion driver/utils/type_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ inline SQLRETURN fillOutputString(
);
}

// ObjectType, that is a pointer type, is treated as an integer, the value of that pointer.
// If ObjectType is a pointer type then obj is treated as an integer corrsponding to the value of that pointer itself.
template <typename ObjectType, typename LengthType1, typename LengthType2>
inline SQLRETURN fillOutputPOD(
const ObjectType & obj,
Expand Down Expand Up @@ -406,6 +406,27 @@ struct SimpleTypeWrapper {
T value;
};

// Values stored exactly as they are written on wire in ODBCDriver2 format.
struct WireTypeAnyAsString
: public SimpleTypeWrapper<std::string>
{
using SimpleTypeWrapper<std::string>::SimpleTypeWrapper;
};

// Date stored exactly as it is represented on wire in RowBinaryWithNamesAndTypes format.
struct WireTypeDateAsInt
: public SimpleTypeWrapper<std::uint16_t>
{
using SimpleTypeWrapper<std::uint16_t>::SimpleTypeWrapper;
};

// DateTime stored exactly as it is represented on wire in RowBinaryWithNamesAndTypes format.
struct WireTypeDateTimeAsInt
: public SimpleTypeWrapper<std::uint32_t>
{
using SimpleTypeWrapper<std::uint32_t>::SimpleTypeWrapper;
};

template <DataSourceTypeId Id> struct DataSourceType; // Leave unimplemented for general case.

template <>
Expand Down Expand Up @@ -565,6 +586,11 @@ template <> struct is_string_data_source_type<DataSourceType<DataSourceTypeId::F
{
};

template <> struct is_string_data_source_type<WireTypeAnyAsString>
: public std::true_type
{
};

template <class T> inline constexpr bool is_string_data_source_type_v = is_string_data_source_type<T>::value;

// Used to avoid duplicate specializations in platforms where 'std::int32_t' or 'std::int64_t' are typedef'd as 'long'.
Expand Down Expand Up @@ -1720,6 +1746,75 @@ namespace value_manip {
};
};

template <>
struct from_value<WireTypeAnyAsString> {
using SourceType = WireTypeAnyAsString;

template <typename DestinationType>
struct to_value {
static inline void convert(const SourceType & src, DestinationType & dest) {
return from_value<std::string>::template to_value<DestinationType>::convert(src.value, dest);
}
};
};

template <>
struct from_value<WireTypeDateAsInt> {
using SourceType = WireTypeDateAsInt;

template <typename DestinationType>
struct to_value {
static inline void convert(const SourceType & src, DestinationType & dest) {
convert_via_proxy<DataSourceType<DataSourceTypeId::Date>>(src, dest);
}
};
};

template <>
struct from_value<WireTypeDateAsInt>::to_value<DataSourceType<DataSourceTypeId::Date>> {
using DestinationType = DataSourceType<DataSourceTypeId::Date>;

static inline void convert(const SourceType & src, DestinationType & dest) {
std::time_t time = src.value;
time = time * 24 * 60 * 60; // Now it's seconds since epoch.
const auto & tm = *std::localtime(&time);

dest.value.year = 1900 + tm.tm_year;
dest.value.month = 1 + tm.tm_mon;
dest.value.day = tm.tm_mday;
}
};

template <>
struct from_value<WireTypeDateTimeAsInt> {
using SourceType = WireTypeDateTimeAsInt;

template <typename DestinationType>
struct to_value {
static inline void convert(const SourceType & src, DestinationType & dest) {
convert_via_proxy<DataSourceType<DataSourceTypeId::DateTime>>(src, dest);
}
};
};

template <>
struct from_value<WireTypeDateTimeAsInt>::to_value<DataSourceType<DataSourceTypeId::DateTime>> {
using DestinationType = DataSourceType<DataSourceTypeId::DateTime>;

static inline void convert(const SourceType & src, DestinationType & dest) {
std::time_t time = src.value;
const auto & tm = *std::localtime(&time);

dest.value.year = 1900 + tm.tm_year;
dest.value.month = 1 + tm.tm_mon;
dest.value.day = tm.tm_mday;
dest.value.hour = tm.tm_hour;
dest.value.minute = tm.tm_min;
dest.value.second = tm.tm_sec;
dest.value.fraction = 0;
}
};

template <typename DestinationType>
struct to_buffer {
template <typename SourceType>
Expand Down