Commit a1e07e38 authored by Vadim Zeitlin's avatar Vadim Zeitlin

Avoid duplicate code for parsing dates in different backends

SQLite, MySQL and PostgreSQL backends used the same but slightly
different code for parsing the contents of a buffer into std::tm struct.

Replace all these different versions with a single version, copied from
the PostgreSQL variant, which seems like the most complete, in the
common code.

Update MySQL-specific test to not expect parsing a string containing
time without date to yield year 2000, this didn't make any sense at all
and PostgreSQL default of year 1900 makes at least slightly more sense.
parent e2f1ca53
......@@ -39,6 +39,11 @@ mktime_from_ymdhms(tm& t,
mktime(&t);
}
// Helper function for parsing datetime values.
//
// Throws if the string in buf couldn't be parsed as a date or a time string.
SOCI_DECL void parse_std_tm(char const *buf, std::tm &t);
} // namespace details
} // namespace soci
......
......@@ -6,68 +6,11 @@
//
#include "common.h"
#include "soci/soci-backend.h"
#include "soci-mktime.h"
#include <ciso646>
#include <cstdlib>
#include <cstring>
#include <ctime>
namespace // anonymous
{
// helper function for parsing decimal data (for std::tm)
long parse10(char const *&p1, char *&p2, const char *msg)
{
long v = std::strtol(p1, &p2, 10);
if (p2 != p1)
{
p1 = p2 + 1;
return v;
}
else
{
throw soci::soci_error(msg);
}
}
} // namespace anonymous
void soci::details::mysql::parse_std_tm(char const *buf, std::tm &t)
{
char const *p1 = buf;
char *p2;
long year, month, day;
long hour = 0, minute = 0, second = 0;
const char *errMsg = "Cannot convert data to std::tm.";
if (strchr(buf, '-') != NULL)
{
year = parse10(p1, p2, errMsg);
month = parse10(p1, p2, errMsg);
day = parse10(p1, p2, errMsg);
}
else
{
year = 2000;
month = 1;
day = 1;
}
if (strchr(buf, ':') != NULL)
{
// there is also the time of day available
hour = parse10(p1, p2, errMsg);
minute = parse10(p1, p2, errMsg);
second = parse10(p1, p2, errMsg);
}
details::mktime_from_ymdhms(t, year, month, day, hour, minute, second);
}
char * soci::details::mysql::quote(MYSQL * conn, const char *s, size_t len)
{
char *retv = new char[2 * len + 3];
......
......@@ -27,9 +27,6 @@ namespace details
namespace mysql
{
// helper function for parsing datetime values
void parse_std_tm(char const *buf, std::tm &t);
// The idea is that infinity - infinity gives NaN, and NaN != NaN is true.
//
// This should work on any IEEE-754-compliant implementation, which is
......
......@@ -11,6 +11,7 @@
#include "soci/soci-platform.h"
#include "common.h"
#include "soci-exchange-cast.h"
#include "soci-mktime.h"
// std
#include <ciso646>
#include <cstdlib>
......
......@@ -8,6 +8,7 @@
#define SOCI_MYSQL_SOURCE
#include "soci/mysql/soci-mysql.h"
#include "soci-mktime.h"
#include "common.h"
#include "soci/soci-platform.h"
#include <ciso646>
......
......@@ -112,9 +112,6 @@ T string_to_unsigned_integer(char const * buf)
}
}
// helper function for parsing datetime values
void parse_std_tm(char const * buf, std::tm & t);
// helper for vector operations
template <typename T>
std::size_t get_vector_size(void * p)
......
......@@ -9,6 +9,7 @@
#include "soci/soci-platform.h"
#include "soci/postgresql/soci-postgresql.h"
#include "soci-cstrtod.h"
#include "soci-mktime.h"
#include "common.h"
#include "soci/rowid.h"
#include "soci/blob.h"
......
......@@ -9,6 +9,7 @@
#include "soci/soci-platform.h"
#include "soci/postgresql/soci-postgresql.h"
#include "soci-cstrtod.h"
#include "soci-mktime.h"
#include "common.h"
#include "soci/type-wrappers.h"
#include <libpq/libpq-fs.h> // libpq
......
//
// Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
#include "soci/soci-platform.h"
#include "common.h"
#include "soci/soci-backend.h"
#include "soci-mktime.h"
// std
#include <cstdlib>
#include <ctime>
namespace // anonymous
{
// helper function for parsing decimal data (for std::tm)
long parse10(char const *&p1, char *&p2, char const* const msg)
{
long v = std::strtol(p1, &p2, 10);
if (p2 != p1)
{
p1 = p2 + 1;
return v;
}
else
{
throw soci::soci_error(msg);
}
}
} // namespace anonymous
void soci::details::sqlite3::parse_std_tm(char const *buf, std::tm &t)
{
char const *p1 = buf;
char *p2 = 0;
char const* const errMsg = "Cannot convert data to std::tm.";
long year = parse10(p1, p2, errMsg);
long month = parse10(p1, p2, errMsg);
long day = parse10(p1, p2, errMsg);
long hour = 0, minute = 0, second = 0;
if (*p2 != '\0')
{
// there is also the time of day available
hour = parse10(p1, p2, errMsg);
minute = parse10(p1, p2, errMsg);
second = parse10(p1, p2, errMsg);
}
details::mktime_from_ymdhms(t, year, month, day, hour, minute, second);
}
......@@ -18,9 +18,6 @@
namespace soci { namespace details { namespace sqlite3 {
// helper function for parsing datetime values
void parse_std_tm(char const *buf, std::tm &t);
// helper for vector operations
template <typename T>
std::size_t get_vector_size(void *p)
......
......@@ -12,6 +12,7 @@
#include "common.h"
#include "soci/blob.h"
#include "soci-cstrtod.h"
#include "soci-mktime.h"
#include "soci-exchange-cast.h"
// std
#include <cstdlib>
......
......@@ -17,6 +17,7 @@
#include "soci/soci-platform.h"
#include "soci/sqlite3/soci-sqlite3.h"
#include "soci-cstrtod.h"
#include "soci-mktime.h"
#include "common.h"
// std
#include <cstddef>
......
//
// Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton
// Copyright (C) 2017 Vadim Zeitlin.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
#include "soci/soci-platform.h"
#include "soci/soci-backend.h"
#define SOCI_SOURCE
#include "soci/error.h"
#include "soci-mktime.h"
#include <cstdlib>
#include <ctime>
#include "common.h"
namespace // anonymous
{
......@@ -32,8 +32,7 @@ long parse10(char const * & p1, char * & p2, char const * msg)
} // namespace anonymous
void soci::details::postgresql::parse_std_tm(char const * buf, std::tm & t)
void soci::details::parse_std_tm(char const * buf, std::tm & t)
{
char const * p1 = buf;
char * p2;
......@@ -82,5 +81,5 @@ void soci::details::postgresql::parse_std_tm(char const * buf, std::tm & t)
}
}
details::mktime_from_ymdhms(t, year, month, day, hour, minute, second);
mktime_from_ymdhms(t, year, month, day, hour, minute, second);
}
......@@ -363,7 +363,7 @@ TEST_CASE("MySQL datetime", "[mysql][datetime]")
soci::session sql(backEnd, connectString);
std::tm t = std::tm();
sql << "select maketime(19, 54, 52)", into(t);
CHECK(t.tm_year == 100);
CHECK(t.tm_year == 0);
CHECK(t.tm_mon == 0);
CHECK(t.tm_mday == 1);
CHECK(t.tm_hour == 19);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment