[odb-users] odb-2.2.1: calling db->persist() twice on the same instance results in two database entries

Hugo.Mildenberger at web.de Hugo.Mildenberger at web.de
Sat Mar 2 06:11:16 EST 2013


  On Sat, 2 Mar 2013 11:21:50 +0100
  Hugo.Mildenberger at web.de wrote:
  > ODB creates two copies of the same instance in the database if db->persist() was called twice on it. I looked up the  documentation but did not found this being documented behaviour. Perhaps I missed something important here? I had expected db->persist() throwing an exception in this case. 


When analysing this problem using gdb, the reason appears to be that odb::database::persist() unconditionally passes "DEFAULT" instead of inserting the already known value for 'id' as it was returned from previous call to persist(). Consequently, st.execute() will never fail for a duplicate entry and thus the exception returned by "object_already_persistent()" will never been thrown, well, except for errors of a very different nature. 


(gdb) bt
#0  odb::access::object_traits_impl<cif::imp::telecom, (odb::database_id)2>::persist (db=..., obj=...)
    at odb/telecom-imp-odb.cxx:446
#1  0x00000000004033b3 in odb::database::persist_<cif::imp::telecom, (odb::database_id)5> (this=0x1cbbf50, obj=...)
    at /usr/include/odb/database.txx:37
#2  0x000000000040329d in odb::database::persist<cif::imp::telecom> (this=0x1cbbf50, obj=...)
    at /usr/include/odb/database.ixx:78
#3  0x0000000000402cc6 in main (argc=1, argv=0x3aeb88f1b68) at telecom.cxx:24


(gdb) list telecom-imp-odb.cxx:446

441           sts.insert_image_version (im.version);
442           imb.version++;
443         }
444
445         insert_statement& st (sts.persist_statement ());
446         if (!st.execute ())
447           throw object_already_persistent ();
448
449         obj._id = static_cast< id_type > (st.id ());
450

(gdb) print obj
$2 = (odb::access::object_traits<cif::imp::telecom>::object_type &) @0x3aeb88f19c0: {_type = "email", _priority = "0", 
  _uri = "sombody.1 at example.com", _purpose = "private", _id = 4}

(gdb) print st
$3 = (
    odb::pgsql::insert_statement &) @0x1cc6fb0: {<odb::pgsql::statement> = {<odb::statement> = {<odb::details::shared_base> = {counter_ = 1, callback_ = 0x0}, _vptr.statement = 0x36ab19a1490 <vtable for odb::pgsql::insert_statement+16>}, 
    conn_ = @0x1cbc120, name_copy_ = "", 
    name_ = 0x408290 <odb::access::object_traits_impl<cif::imp::telecom, (odb::database_id)2>::persist_statement_name> "cif_imp_telecom_persist", text_copy_ = "", 
    text_ = 0x408360 <odb::access::object_traits_impl<cif::imp::telecom, (odb::database_id)2>::persist_statement> "INSERT INTO \"telecom\" (\"type\",\"priority\",\"uri\",\"purpose\",\"id\") VALUES ($1,$2,$3,$4,DEFAULT) RETURNING \"id\"", 
    deallocated_ = false}, param_ = @0x1cc7348, native_param_ = @0x1cc7420, returning_ = true, id_ = 4}





More information about the odb-users mailing list