[odb-users] Object creator with boost::posix_time::ptime member : exception from boost

Boris Kolpackov boris at codesynthesis.com
Thu Jun 6 13:12:45 EDT 2013


Hi,

rkadeFR <contact at rkade.fr> writes:

> 1- I can't change the database
> 2- It's used as a negative infinite value :s

Ok, so mapping it to neg_infin would be more appropriate.


> If I understand, ODB construct an empty object with the private
> cTor, and then fill the member with some copy?

That's about right. The exception is thrown when ODB tries to
initialize an instance of ptime from the loaded value, before
assigning it to the data member in the object.


> Can I change the behavior of this copy to handle the exception?

Yes, ODB allows you to provide completely custom code that converts
between the database value (in your case, that would be MYSQL_TIME
struct) and C++ value (that would be ptime). There you can do pretty
much any conversions you want. Also, if you are going this route,
then you can also map DATETIME to something other than Boost ptime
(e.g., your own date-time representation or struct tm). This guide
has detailed information on how to do all this:

http://www.codesynthesis.com/~boris/blog/2012/10/16/custom-cxx-to-database-type-mapping-in-odb/

You can also use the odb/boost/date-time/mysql/posix-time-traits.hxx
file from the libodb-boost as a reference.

There is also another option which doesn't require a custom value_traits
specialization. It is a bit "hackish" (or cool; depending on how you look
at it ;-)) and is better suited for once-off customizations that are only
needed in specific classes. The overall idea is to use virtual data members
and use the image type (MYSQL_TIME in our case) as its type. We will also
need to provide our own accessors/modifiers that convert between our
data member (or ptime type) and the image type. Here is an outline:

#include <mysql/mysql.h> // MYSQL_TIME

class Person
{
  ...

  void tsAddedConvert (const MYSQL_TIME& v)
  {
    using namespace boost::gregorian;
    using namespace boost::posix_time;

    if (v.year == 0 &&
        v.month == 0 &&
        v.day == 0 &&
        v.hour == 0 &&
        v.minute == 0 &&
        v.second == 0)
      tsAdded = ptime (neg_infin);
    else
      tsAdded = ptime (date (v.year, v.month, v.day),
                       time_duration (v.hour, v.minute, v.second));
  }

  MYSQL_TIME tsAddedConvert () const
  {
    using namespace boost::gregorian;
    using namespace boost::posix_time;

    MYSQL_TIME v;
    v.neg = false;

    if (tsAdded.is_neg_infinity ())
    {
      v.year = 0;
      v.month = 0;
      v.day = 0;

      v.hour = 0;
      v.minute = 0;
      v.second = 0;
    }
    else
    {
      const date& d (tsAdded.date ());
      v.year = d.year ();
      v.month = d.month ();
      v.day = d.day ();

      const time_duration& t (tsAdded.time_of_day ());
      v.hour = t.hours ();
      v.minute = t.minutes ();
      v.second = t.seconds ();
    }

    v.second_part = 0;
    return v;
  }

  #pragma db column("dateTime") type("DATETIME")
  #pragma db member(dateTime) virtual(MYSQL_TIME) access(tsAddedConvert)

  #pragma db transient
  boost::posix_time::ptime tsAdded;
};

It is also possible to forward to the default ptime value_traits for
the default cases (we would need to move the tsAddedConvert() functions
to the .cxx file though).

Boris



More information about the odb-users mailing list