[odb-users] Problem with bi-directional one-to-many relationship

Louis Marascio marascio at gmail.com
Tue Apr 29 16:39:49 EDT 2014


Hi folks,

I've run into an issue that I'm unable to solve myself. I have a simple
bi-directional one-to-many relationship between two tables. The tables look
like this:

CREATE TABLE locations (
    id   SERIAL PRIMARY KEY,
    name TEXT NOT NULL
);

CREATE TABLE servers (
    id          SERIAL PRIMARY KEY,
    hostname    TEXT NOT NULL,
    location_id INTEGER REFERENCES locations(id) NOT NULL
);


FWIW, this database schema is NOT managed by ODB. My application requires
ODB to map to an existing schema.

The mappings are equally simplistic, as you can imagine. The fields of
interest are mapped as follows (partial classes shown, of course):

class Location
{
  private:
     #pragma db id auto
    unsigned long id_;

    #pragma db value_not_null inverse(location_)
    Servers_type servers_;
};


class Server
{
  private:
    #pragma db id auto
    unsigned long id_;

    #pragma db not_null column("location_id")
    Location_ptr location_;
};


This is, I believe, nearly identical to the example shown in the
documentation. Location_ptr and Server_ptr are both std::shared_ptr
typedefs for their respective classes. I have attempted with both std::weak_ptr
and odb::lazy_weak_ptr with no change to the outcome.

The error I'm running into is simple: I can persist these objects without
issue. I have verified that the database contains the correct rows with
correct IDs. When I try to load() a Location, I receive an
odb::object_not_persistent error. In examining the PostgreSQL log files, I
see the following:

execute Location_find: SELECT "locations"."id", "locations"."name" FROM
"locations" WHERE "locations"."id"=$1
parameters: $1 = '1'

execute Location_servers_select: SELECT "servers"."id" FROM "servers" WHERE
"servers"."location_id"=$1
parameters: $1 = '1'

execute Server_find: SELECT "servers"."id", "servers"."hostname",
 "servers"."location_id" FROM "servers" WHERE "servers"."id"=$1
parameters: $1 = '4294967296'


The ID is correct for the first two SELECT statements, but is garbage for
the SELECT that loads the Servers for the Location. The garbage ID is
suspiciously 0xFFFFFFFF + 1.

A pattern exists as well. If I re-run the test program, the failing ID
is 8589934592. Run it a third time, and it is 12884901888. Each failed run
increments the garbage ID by 0xFFFFFFFF + 1.

The load() works if I use odb::lazy_weak_ptr in the vector of Servers
within Location. However, when I attempt to .load() the lazy_weak_ptr I hit
the same issue.

I have attempted to debug this but I'm afraid my understanding of the ODB
internals is lacking. I don't think its a bug on my side, but would be
relieved to have a trivial error in my own code pointed out to me. I have
created a reproducible test case that can be downloaded here:

https://dl.dropboxusercontent.com/u/140772/lrm_odbtest.tar.gz


Inside the archive you'll find the simple test driver, database models, SQL
script to make the databsae, and a Makefile. You'll also find the
PostgreSQL statement log that I captured while running the test program. I
have annotated it pointing out the important pieces, as far as I can tell.

ODB 2.3.0
libodb 2.3.0
libodb-pgsql 2.3.1
PostgreSQL 9.3.2
g++ 4.6.4
Linux 3.12.9 x86_64 (Arch linux, if that matters)

The ODB compiler was not built from source. I am using the compiler
binaries as provided on the downloads section of the website. libodb and
libodb-pgsql were, of course, built from source.

Thank you, and please let me know if there is any additional data or detail
that you need.

Louis

---
Louis R. Marascio
512-964-4569


More information about the odb-users mailing list