// -*- C++ -*-
//
// This file was generated by ODB, object-relational mapping (ORM)
// compiler for C++.
//

#include <odb/pre.hxx>

#include <bpkg/fetch-cache-data-odb.hxx>

#include <cassert>
#include <cstring>  // std::memcpy

#include <odb/schema-catalog-impl.hxx>

#include <odb/sqlite/traits.hxx>
#include <odb/sqlite/database.hxx>
#include <odb/sqlite/transaction.hxx>
#include <odb/sqlite/connection.hxx>
#include <odb/sqlite/statement.hxx>
#include <odb/sqlite/statement-cache.hxx>
#include <odb/sqlite/simple-object-statements.hxx>
#include <odb/sqlite/view-statements.hxx>
#include <odb/sqlite/section-statements.hxx>
#include <odb/sqlite/container-statements.hxx>
#include <odb/sqlite/exceptions.hxx>
#include <odb/sqlite/simple-object-result.hxx>
#include <odb/sqlite/view-result.hxx>

namespace odb
{
  // pkg_repository_auth
  //

  struct access::object_traits_impl< ::bpkg::pkg_repository_auth, id_sqlite >::extra_statement_cache_type
  {
    extra_statement_cache_type (
      sqlite::connection&,
      image_type&,
      id_image_type&,
      sqlite::binding&,
      sqlite::binding&)
    {
    }
  };

  access::object_traits_impl< ::bpkg::pkg_repository_auth, id_sqlite >::id_type
  access::object_traits_impl< ::bpkg::pkg_repository_auth, id_sqlite >::
  id (const image_type& i)
  {
    sqlite::database* db (0);
    ODB_POTENTIALLY_UNUSED (db);

    id_type id;
    {
      sqlite::value_traits<
          ::std::string,
          sqlite::id_text >::set_value (
        id,
        i.id_value,
        i.id_size,
        i.id_null);
    }

    return id;
  }

  bool access::object_traits_impl< ::bpkg::pkg_repository_auth, id_sqlite >::
  grow (image_type& i,
        bool* t)
  {
    ODB_POTENTIALLY_UNUSED (i);
    ODB_POTENTIALLY_UNUSED (t);

    bool grew (false);

    // id
    //
    if (t[0UL])
    {
      i.id_value.capacity (i.id_size);
      grew = true;
    }

    // fingerprint
    //
    if (t[1UL])
    {
      i.fingerprint_value.capacity (i.fingerprint_size);
      grew = true;
    }

    // name
    //
    if (t[2UL])
    {
      i.name_value.capacity (i.name_size);
      grew = true;
    }

    // end_date
    //
    t[3UL] = false;

    return grew;
  }

  void access::object_traits_impl< ::bpkg::pkg_repository_auth, id_sqlite >::
  bind (sqlite::bind* b,
        image_type& i,
        sqlite::statement_kind sk)
  {
    ODB_POTENTIALLY_UNUSED (sk);

    using namespace sqlite;

    std::size_t n (0);

    // id
    //
    if (sk != statement_update)
    {
      b[n].type = sqlite::image_traits<
        ::std::string,
        sqlite::id_text>::bind_value;
      b[n].buffer = i.id_value.data ();
      b[n].size = &i.id_size;
      b[n].capacity = i.id_value.capacity ();
      b[n].is_null = &i.id_null;
      n++;
    }

    // fingerprint
    //
    b[n].type = sqlite::image_traits<
      ::std::string,
      sqlite::id_text>::bind_value;
    b[n].buffer = i.fingerprint_value.data ();
    b[n].size = &i.fingerprint_size;
    b[n].capacity = i.fingerprint_value.capacity ();
    b[n].is_null = &i.fingerprint_null;
    n++;

    // name
    //
    b[n].type = sqlite::image_traits<
      ::std::string,
      sqlite::id_text>::bind_value;
    b[n].buffer = i.name_value.data ();
    b[n].size = &i.name_size;
    b[n].capacity = i.name_value.capacity ();
    b[n].is_null = &i.name_null;
    n++;

    // end_date
    //
    b[n].type = sqlite::bind::integer;
    b[n].buffer = &i.end_date_value;
    b[n].is_null = &i.end_date_null;
    n++;
  }

  void access::object_traits_impl< ::bpkg::pkg_repository_auth, id_sqlite >::
  bind (sqlite::bind* b, id_image_type& i)
  {
    std::size_t n (0);
    b[n].type = sqlite::image_traits<
      ::std::string,
      sqlite::id_text>::bind_value;
    b[n].buffer = i.id_value.data ();
    b[n].size = &i.id_size;
    b[n].capacity = i.id_value.capacity ();
    b[n].is_null = &i.id_null;
  }

  bool access::object_traits_impl< ::bpkg::pkg_repository_auth, id_sqlite >::
  init (image_type& i,
        const object_type& o,
        sqlite::statement_kind sk)
  {
    ODB_POTENTIALLY_UNUSED (i);
    ODB_POTENTIALLY_UNUSED (o);
    ODB_POTENTIALLY_UNUSED (sk);

    using namespace sqlite;

    bool grew (false);

    // id
    //
    if (sk == statement_insert)
    {
      ::std::string const& v =
        o.id;

      bool is_null (false);
      std::size_t cap (i.id_value.capacity ());
      sqlite::value_traits<
          ::std::string,
          sqlite::id_text >::set_image (
        i.id_value,
        i.id_size,
        is_null,
        v);
      i.id_null = is_null;
      grew = grew || (cap != i.id_value.capacity ());
    }

    // fingerprint
    //
    {
      ::std::string const& v =
        o.fingerprint;

      bool is_null (false);
      std::size_t cap (i.fingerprint_value.capacity ());
      sqlite::value_traits<
          ::std::string,
          sqlite::id_text >::set_image (
        i.fingerprint_value,
        i.fingerprint_size,
        is_null,
        v);
      i.fingerprint_null = is_null;
      grew = grew || (cap != i.fingerprint_value.capacity ());
    }

    // name
    //
    {
      ::std::string const& v =
        o.name;

      bool is_null (false);
      std::size_t cap (i.name_value.capacity ());
      sqlite::value_traits<
          ::std::string,
          sqlite::id_text >::set_image (
        i.name_value,
        i.name_size,
        is_null,
        v);
      i.name_null = is_null;
      grew = grew || (cap != i.name_value.capacity ());
    }

    // end_date
    //
    {
      ::bpkg::optional_timestamp const& v =
        o.end_date;

      // From package-common.hxx:112:14
      ::bpkg::optional_uint64_t const& vt =
        (v) ? std::chrono::duration_cast < std::chrono::nanoseconds > ((v)->time_since_epoch ()).count () : bpkg::optional_uint64_t ();

      bool is_null (true);
      sqlite::value_traits<
          ::bpkg::optional_uint64_t,
          sqlite::id_integer >::set_image (
        i.end_date_value,
        is_null,
        vt);
      i.end_date_null = is_null;
    }

    return grew;
  }

  void access::object_traits_impl< ::bpkg::pkg_repository_auth, id_sqlite >::
  init (object_type& o,
        const image_type& i,
        database* db)
  {
    ODB_POTENTIALLY_UNUSED (o);
    ODB_POTENTIALLY_UNUSED (i);
    ODB_POTENTIALLY_UNUSED (db);

    // id
    //
    {
      ::std::string& v =
        o.id;

      sqlite::value_traits<
          ::std::string,
          sqlite::id_text >::set_value (
        v,
        i.id_value,
        i.id_size,
        i.id_null);
    }

    // fingerprint
    //
    {
      ::std::string& v =
        o.fingerprint;

      sqlite::value_traits<
          ::std::string,
          sqlite::id_text >::set_value (
        v,
        i.fingerprint_value,
        i.fingerprint_size,
        i.fingerprint_null);
    }

    // name
    //
    {
      ::std::string& v =
        o.name;

      sqlite::value_traits<
          ::std::string,
          sqlite::id_text >::set_value (
        v,
        i.name_value,
        i.name_size,
        i.name_null);
    }

    // end_date
    //
    {
      ::bpkg::optional_timestamp& v =
        o.end_date;

      ::bpkg::optional_uint64_t vt;

      sqlite::value_traits<
          ::bpkg::optional_uint64_t,
          sqlite::id_integer >::set_value (
        vt,
        i.end_date_value,
        i.end_date_null);

      // From package-common.hxx:112:14
      v = (vt) ? bpkg::timestamp (std::chrono::duration_cast < bpkg::timestamp::duration > (std::chrono::nanoseconds ( * (vt)))) : bpkg::optional_timestamp ();
    }
  }

  void access::object_traits_impl< ::bpkg::pkg_repository_auth, id_sqlite >::
  init (id_image_type& i, const id_type& id)
  {
    bool grew (false);
    {
      bool is_null (false);
      std::size_t cap (i.id_value.capacity ());
      sqlite::value_traits<
          ::std::string,
          sqlite::id_text >::set_image (
        i.id_value,
        i.id_size,
        is_null,
        id);
      i.id_null = is_null;
      grew = grew || (cap != i.id_value.capacity ());
    }

    if (grew)
      i.version++;
  }

  const char access::object_traits_impl< ::bpkg::pkg_repository_auth, id_sqlite >::persist_statement[] =
  "INSERT INTO \"pkg_repository_auth\" "
  "(\"id\", "
  "\"fingerprint\", "
  "\"name\", "
  "\"end_date\") "
  "VALUES "
  "(?, ?, ?, ?)";

  const char access::object_traits_impl< ::bpkg::pkg_repository_auth, id_sqlite >::find_statement[] =
  "SELECT "
  "\"pkg_repository_auth\".\"id\", "
  "\"pkg_repository_auth\".\"fingerprint\", "
  "\"pkg_repository_auth\".\"name\", "
  "\"pkg_repository_auth\".\"end_date\" "
  "FROM \"pkg_repository_auth\" "
  "WHERE \"pkg_repository_auth\".\"id\"=?";

  const char access::object_traits_impl< ::bpkg::pkg_repository_auth, id_sqlite >::update_statement[] =
  "UPDATE \"pkg_repository_auth\" "
  "SET "
  "\"fingerprint\"=?, "
  "\"name\"=?, "
  "\"end_date\"=? "
  "WHERE \"id\"=?";

  const char access::object_traits_impl< ::bpkg::pkg_repository_auth, id_sqlite >::erase_statement[] =
  "DELETE FROM \"pkg_repository_auth\" "
  "WHERE \"id\"=?";

  const char access::object_traits_impl< ::bpkg::pkg_repository_auth, id_sqlite >::query_statement[] =
  "SELECT "
  "\"pkg_repository_auth\".\"id\", "
  "\"pkg_repository_auth\".\"fingerprint\", "
  "\"pkg_repository_auth\".\"name\", "
  "\"pkg_repository_auth\".\"end_date\" "
  "FROM \"pkg_repository_auth\"";

  const char access::object_traits_impl< ::bpkg::pkg_repository_auth, id_sqlite >::erase_query_statement[] =
  "DELETE FROM \"pkg_repository_auth\"";

  const char access::object_traits_impl< ::bpkg::pkg_repository_auth, id_sqlite >::table_name[] =
  "\"pkg_repository_auth\"";

  void access::object_traits_impl< ::bpkg::pkg_repository_auth, id_sqlite >::
  persist (database& db, const object_type& obj)
  {
    using namespace sqlite;

    sqlite::connection& conn (
      sqlite::transaction::current ().connection (db));
    statements_type& sts (
      conn.statement_cache ().find_object<object_type> ());

    callback (db,
              obj,
              callback_event::pre_persist);

    image_type& im (sts.image ());
    binding& imb (sts.insert_image_binding ());

    if (init (im, obj, statement_insert))
      im.version++;

    if (im.version != sts.insert_image_version () ||
        imb.version == 0)
    {
      bind (imb.bind, im, statement_insert);
      sts.insert_image_version (im.version);
      imb.version++;
    }

    insert_statement& st (sts.persist_statement ());
    if (!st.execute ())
      throw object_already_persistent ();

    callback (db,
              obj,
              callback_event::post_persist);
  }

  void access::object_traits_impl< ::bpkg::pkg_repository_auth, id_sqlite >::
  update (database& db, const object_type& obj)
  {
    ODB_POTENTIALLY_UNUSED (db);

    using namespace sqlite;
    using sqlite::update_statement;

    callback (db, obj, callback_event::pre_update);

    sqlite::transaction& tr (sqlite::transaction::current ());
    sqlite::connection& conn (tr.connection (db));
    statements_type& sts (
      conn.statement_cache ().find_object<object_type> ());

    id_image_type& idi (sts.id_image ());
    init (idi, id (obj));

    image_type& im (sts.image ());
    if (init (im, obj, statement_update))
      im.version++;

    bool u (false);
    binding& imb (sts.update_image_binding ());
    if (im.version != sts.update_image_version () ||
        imb.version == 0)
    {
      bind (imb.bind, im, statement_update);
      sts.update_image_version (im.version);
      imb.version++;
      u = true;
    }

    binding& idb (sts.id_image_binding ());
    if (idi.version != sts.update_id_image_version () ||
        idb.version == 0)
    {
      if (idi.version != sts.id_image_version () ||
          idb.version == 0)
      {
        bind (idb.bind, idi);
        sts.id_image_version (idi.version);
        idb.version++;
      }

      sts.update_id_image_version (idi.version);

      if (!u)
        imb.version++;
    }

    update_statement& st (sts.update_statement ());
    if (st.execute () == 0)
      throw object_not_persistent ();

    callback (db, obj, callback_event::post_update);
    pointer_cache_traits::update (db, obj);
  }

  void access::object_traits_impl< ::bpkg::pkg_repository_auth, id_sqlite >::
  erase (database& db, const id_type& id)
  {
    using namespace sqlite;

    sqlite::connection& conn (
      sqlite::transaction::current ().connection (db));
    statements_type& sts (
      conn.statement_cache ().find_object<object_type> ());

    id_image_type& i (sts.id_image ());
    init (i, id);

    binding& idb (sts.id_image_binding ());
    if (i.version != sts.id_image_version () || idb.version == 0)
    {
      bind (idb.bind, i);
      sts.id_image_version (i.version);
      idb.version++;
    }

    if (sts.erase_statement ().execute () != 1)
      throw object_not_persistent ();

    pointer_cache_traits::erase (db, id);
  }

  access::object_traits_impl< ::bpkg::pkg_repository_auth, id_sqlite >::pointer_type
  access::object_traits_impl< ::bpkg::pkg_repository_auth, id_sqlite >::
  find (database& db, const id_type& id)
  {
    using namespace sqlite;

    {
      pointer_type p (pointer_cache_traits::find (db, id));

      if (!pointer_traits::null_ptr (p))
        return p;
    }

    sqlite::connection& conn (
      sqlite::transaction::current ().connection (db));
    statements_type& sts (
      conn.statement_cache ().find_object<object_type> ());

    statements_type::auto_lock l (sts);

    if (l.locked ())
    {
      if (!find_ (sts, &id))
        return pointer_type ();
    }

    pointer_type p (
      access::object_factory<object_type, pointer_type>::create ());
    pointer_traits::guard pg (p);

    pointer_cache_traits::insert_guard ig (
      pointer_cache_traits::insert (db, id, p));

    object_type& obj (pointer_traits::get_ref (p));

    if (l.locked ())
    {
      select_statement& st (sts.find_statement ());
      ODB_POTENTIALLY_UNUSED (st);

      callback (db, obj, callback_event::pre_load);
      init (obj, sts.image (), &db);
      load_ (sts, obj, false);
      sts.load_delayed (0);
      l.unlock ();
      callback (db, obj, callback_event::post_load);
      pointer_cache_traits::load (ig.position ());
    }
    else
      sts.delay_load (id, obj, ig.position ());

    ig.release ();
    pg.release ();
    return p;
  }

  bool access::object_traits_impl< ::bpkg::pkg_repository_auth, id_sqlite >::
  find (database& db, const id_type& id, object_type& obj)
  {
    using namespace sqlite;

    sqlite::connection& conn (
      sqlite::transaction::current ().connection (db));
    statements_type& sts (
      conn.statement_cache ().find_object<object_type> ());

    statements_type::auto_lock l (sts);
    assert (l.locked ()) /* Must be a top-level call. */;

    if (!find_ (sts, &id))
      return false;

    select_statement& st (sts.find_statement ());
    ODB_POTENTIALLY_UNUSED (st);

    reference_cache_traits::position_type pos (
      reference_cache_traits::insert (db, id, obj));
    reference_cache_traits::insert_guard ig (pos);

    callback (db, obj, callback_event::pre_load);
    init (obj, sts.image (), &db);
    load_ (sts, obj, false);
    sts.load_delayed (0);
    l.unlock ();
    callback (db, obj, callback_event::post_load);
    reference_cache_traits::load (pos);
    ig.release ();
    return true;
  }

  bool access::object_traits_impl< ::bpkg::pkg_repository_auth, id_sqlite >::
  reload (database& db, object_type& obj)
  {
    using namespace sqlite;

    sqlite::connection& conn (
      sqlite::transaction::current ().connection (db));
    statements_type& sts (
      conn.statement_cache ().find_object<object_type> ());

    statements_type::auto_lock l (sts);
    assert (l.locked ()) /* Must be a top-level call. */;

    const id_type& id (object_traits_impl::id (obj));
    if (!find_ (sts, &id))
      return false;

    select_statement& st (sts.find_statement ());
    ODB_POTENTIALLY_UNUSED (st);

    callback (db, obj, callback_event::pre_load);
    init (obj, sts.image (), &db);
    load_ (sts, obj, true);
    sts.load_delayed (0);
    l.unlock ();
    callback (db, obj, callback_event::post_load);
    return true;
  }

  bool access::object_traits_impl< ::bpkg::pkg_repository_auth, id_sqlite >::
  find_ (statements_type& sts,
         const id_type* id)
  {
    using namespace sqlite;

    id_image_type& i (sts.id_image ());
    init (i, *id);

    binding& idb (sts.id_image_binding ());
    if (i.version != sts.id_image_version () || idb.version == 0)
    {
      bind (idb.bind, i);
      sts.id_image_version (i.version);
      idb.version++;
    }

    image_type& im (sts.image ());
    binding& imb (sts.select_image_binding ());

    if (im.version != sts.select_image_version () ||
        imb.version == 0)
    {
      bind (imb.bind, im, statement_select);
      sts.select_image_version (im.version);
      imb.version++;
    }

    select_statement& st (sts.find_statement ());

    st.execute ();
    auto_result ar (st);
    select_statement::result r (st.fetch ());

    if (r == select_statement::truncated)
    {
      if (grow (im, sts.select_image_truncated ()))
        im.version++;

      if (im.version != sts.select_image_version ())
      {
        bind (imb.bind, im, statement_select);
        sts.select_image_version (im.version);
        imb.version++;
        st.refetch ();
      }
    }

    return r != select_statement::no_data;
  }

  result< access::object_traits_impl< ::bpkg::pkg_repository_auth, id_sqlite >::object_type >
  access::object_traits_impl< ::bpkg::pkg_repository_auth, id_sqlite >::
  query (database& db, const query_base_type& q)
  {
    using namespace sqlite;
    using odb::details::shared;
    using odb::details::shared_ptr;

    sqlite::connection& conn (
      sqlite::transaction::current ().connection (db));

    statements_type& sts (
      conn.statement_cache ().find_object<object_type> ());

    image_type& im (sts.image ());
    binding& imb (sts.select_image_binding ());

    if (im.version != sts.select_image_version () ||
        imb.version == 0)
    {
      bind (imb.bind, im, statement_select);
      sts.select_image_version (im.version);
      imb.version++;
    }

    std::string text (query_statement);
    if (!q.empty ())
    {
      text += " ";
      text += q.clause ();
    }

    q.init_parameters ();
    shared_ptr<select_statement> st (
      new (shared) select_statement (
        conn,
        text,
        false,
        true,
        q.parameters_binding (),
        imb));

    st->execute ();

    shared_ptr< odb::object_result_impl<object_type> > r (
      new (shared) sqlite::object_result_impl<object_type> (
        q, st, sts, 0));

    return result<object_type> (r);
  }

  unsigned long long access::object_traits_impl< ::bpkg::pkg_repository_auth, id_sqlite >::
  erase_query (database& db, const query_base_type& q)
  {
    using namespace sqlite;

    sqlite::connection& conn (
      sqlite::transaction::current ().connection (db));

    std::string text (erase_query_statement);
    if (!q.empty ())
    {
      text += ' ';
      text += q.clause ();
    }

    q.init_parameters ();
    delete_statement st (
      conn,
      text,
      q.parameters_binding ());

    return st.execute ();
  }

  // pkg_repository_auth_count
  //

  bool access::view_traits_impl< ::bpkg::pkg_repository_auth_count, id_sqlite >::
  grow (image_type& i,
        bool* t)
  {
    ODB_POTENTIALLY_UNUSED (i);
    ODB_POTENTIALLY_UNUSED (t);

    bool grew (false);

    // result
    //
    t[0UL] = false;

    return grew;
  }

  void access::view_traits_impl< ::bpkg::pkg_repository_auth_count, id_sqlite >::
  bind (sqlite::bind* b,
        image_type& i)
  {
    using namespace sqlite;

    sqlite::statement_kind sk (statement_select);
    ODB_POTENTIALLY_UNUSED (sk);

    std::size_t n (0);

    // result
    //
    b[n].type = sqlite::bind::integer;
    b[n].buffer = &i.result_value;
    b[n].is_null = &i.result_null;
    n++;
  }

  void access::view_traits_impl< ::bpkg::pkg_repository_auth_count, id_sqlite >::
  init (view_type& o,
        const image_type& i,
        database* db)
  {
    ODB_POTENTIALLY_UNUSED (o);
    ODB_POTENTIALLY_UNUSED (i);
    ODB_POTENTIALLY_UNUSED (db);

    // result
    //
    {
      ::std::size_t& v =
        o.result;

      sqlite::value_traits<
          ::std::size_t,
          sqlite::id_integer >::set_value (
        v,
        i.result_value,
        i.result_null);
    }
  }

  access::view_traits_impl< ::bpkg::pkg_repository_auth_count, id_sqlite >::query_base_type
  access::view_traits_impl< ::bpkg::pkg_repository_auth_count, id_sqlite >::
  query_statement (const query_base_type& q)
  {
    query_base_type r (
      "SELECT "
      "count(*) ");

    r += "FROM \"pkg_repository_auth\"";

    if (!q.empty ())
    {
      r += " ";
      r += q.clause_prefix ();
      r += q;
    }

    return r;
  }

  result< access::view_traits_impl< ::bpkg::pkg_repository_auth_count, id_sqlite >::view_type >
  access::view_traits_impl< ::bpkg::pkg_repository_auth_count, id_sqlite >::
  query (database& db, const query_base_type& q)
  {
    using namespace sqlite;
    using odb::details::shared;
    using odb::details::shared_ptr;

    sqlite::connection& conn (
      sqlite::transaction::current ().connection (db));
    statements_type& sts (
      conn.statement_cache ().find_view<view_type> ());

    image_type& im (sts.image ());
    binding& imb (sts.image_binding ());

    if (im.version != sts.image_version () || imb.version == 0)
    {
      bind (imb.bind, im);
      sts.image_version (im.version);
      imb.version++;
    }

    const query_base_type& qs (query_statement (q));
    qs.init_parameters ();
    shared_ptr<select_statement> st (
      new (shared) select_statement (
        conn,
        qs.clause (),
        false,
        true,
        qs.parameters_binding (),
        imb));

    st->execute ();

    shared_ptr< odb::view_result_impl<view_type> > r (
      new (shared) sqlite::view_result_impl<view_type> (
        qs, st, sts, 0));

    return result<view_type> (r);
  }

  // pkg_repository_metadata
  //

  struct access::object_traits_impl< ::bpkg::pkg_repository_metadata, id_sqlite >::extra_statement_cache_type
  {
    extra_statement_cache_type (
      sqlite::connection&,
      image_type&,
      id_image_type&,
      sqlite::binding&,
      sqlite::binding&)
    {
    }
  };

  access::object_traits_impl< ::bpkg::pkg_repository_metadata, id_sqlite >::id_type
  access::object_traits_impl< ::bpkg::pkg_repository_metadata, id_sqlite >::
  id (const image_type& i)
  {
    sqlite::database* db (0);
    ODB_POTENTIALLY_UNUSED (db);

    id_type id;
    {
      sqlite::value_traits<
          ::bpkg::repository_url,
          sqlite::id_text >::set_value (
        id,
        i.url_value,
        i.url_size,
        i.url_null);
    }

    return id;
  }

  bool access::object_traits_impl< ::bpkg::pkg_repository_metadata, id_sqlite >::
  grow (image_type& i,
        bool* t)
  {
    ODB_POTENTIALLY_UNUSED (i);
    ODB_POTENTIALLY_UNUSED (t);

    bool grew (false);

    // url
    //
    if (t[0UL])
    {
      i.url_value.capacity (i.url_size);
      grew = true;
    }

    // directory
    //
    if (t[1UL])
    {
      i.directory_value.capacity (i.directory_size);
      grew = true;
    }

    // session
    //
    if (t[2UL])
    {
      i.session_value.capacity (i.session_size);
      grew = true;
    }

    // access_time
    //
    t[3UL] = false;

    // repositories_path
    //
    if (t[4UL])
    {
      i.repositories_path_value.capacity (i.repositories_path_size);
      grew = true;
    }

    // repositories_checksum
    //
    if (t[5UL])
    {
      i.repositories_checksum_value.capacity (i.repositories_checksum_size);
      grew = true;
    }

    // packages_path
    //
    if (t[6UL])
    {
      i.packages_path_value.capacity (i.packages_path_size);
      grew = true;
    }

    // packages_checksum
    //
    if (t[7UL])
    {
      i.packages_checksum_value.capacity (i.packages_checksum_size);
      grew = true;
    }

    return grew;
  }

  void access::object_traits_impl< ::bpkg::pkg_repository_metadata, id_sqlite >::
  bind (sqlite::bind* b,
        image_type& i,
        sqlite::statement_kind sk)
  {
    ODB_POTENTIALLY_UNUSED (sk);

    using namespace sqlite;

    std::size_t n (0);

    // url
    //
    if (sk != statement_update)
    {
      b[n].type = sqlite::image_traits<
        ::bpkg::repository_url,
        sqlite::id_text>::bind_value;
      b[n].buffer = i.url_value.data ();
      b[n].size = &i.url_size;
      b[n].capacity = i.url_value.capacity ();
      b[n].is_null = &i.url_null;
      n++;
    }

    // directory
    //
    b[n].type = sqlite::image_traits<
      ::std::string,
      sqlite::id_text>::bind_value;
    b[n].buffer = i.directory_value.data ();
    b[n].size = &i.directory_size;
    b[n].capacity = i.directory_value.capacity ();
    b[n].is_null = &i.directory_null;
    n++;

    // session
    //
    b[n].type = sqlite::image_traits<
      ::std::string,
      sqlite::id_text>::bind_value;
    b[n].buffer = i.session_value.data ();
    b[n].size = &i.session_size;
    b[n].capacity = i.session_value.capacity ();
    b[n].is_null = &i.session_null;
    n++;

    // access_time
    //
    b[n].type = sqlite::bind::integer;
    b[n].buffer = &i.access_time_value;
    b[n].is_null = &i.access_time_null;
    n++;

    // repositories_path
    //
    b[n].type = sqlite::image_traits<
      ::std::string,
      sqlite::id_text>::bind_value;
    b[n].buffer = i.repositories_path_value.data ();
    b[n].size = &i.repositories_path_size;
    b[n].capacity = i.repositories_path_value.capacity ();
    b[n].is_null = &i.repositories_path_null;
    n++;

    // repositories_checksum
    //
    b[n].type = sqlite::image_traits<
      ::std::string,
      sqlite::id_text>::bind_value;
    b[n].buffer = i.repositories_checksum_value.data ();
    b[n].size = &i.repositories_checksum_size;
    b[n].capacity = i.repositories_checksum_value.capacity ();
    b[n].is_null = &i.repositories_checksum_null;
    n++;

    // packages_path
    //
    b[n].type = sqlite::image_traits<
      ::std::string,
      sqlite::id_text>::bind_value;
    b[n].buffer = i.packages_path_value.data ();
    b[n].size = &i.packages_path_size;
    b[n].capacity = i.packages_path_value.capacity ();
    b[n].is_null = &i.packages_path_null;
    n++;

    // packages_checksum
    //
    b[n].type = sqlite::image_traits<
      ::std::string,
      sqlite::id_text>::bind_value;
    b[n].buffer = i.packages_checksum_value.data ();
    b[n].size = &i.packages_checksum_size;
    b[n].capacity = i.packages_checksum_value.capacity ();
    b[n].is_null = &i.packages_checksum_null;
    n++;
  }

  void access::object_traits_impl< ::bpkg::pkg_repository_metadata, id_sqlite >::
  bind (sqlite::bind* b, id_image_type& i)
  {
    std::size_t n (0);
    b[n].type = sqlite::image_traits<
      ::bpkg::repository_url,
      sqlite::id_text>::bind_value;
    b[n].buffer = i.id_value.data ();
    b[n].size = &i.id_size;
    b[n].capacity = i.id_value.capacity ();
    b[n].is_null = &i.id_null;
  }

  bool access::object_traits_impl< ::bpkg::pkg_repository_metadata, id_sqlite >::
  init (image_type& i,
        const object_type& o,
        sqlite::statement_kind sk)
  {
    ODB_POTENTIALLY_UNUSED (i);
    ODB_POTENTIALLY_UNUSED (o);
    ODB_POTENTIALLY_UNUSED (sk);

    using namespace sqlite;

    bool grew (false);

    // url
    //
    if (sk == statement_insert)
    {
      ::bpkg::repository_url const& v =
        o.url;

      bool is_null (false);
      std::size_t cap (i.url_value.capacity ());
      sqlite::value_traits<
          ::bpkg::repository_url,
          sqlite::id_text >::set_image (
        i.url_value,
        i.url_size,
        is_null,
        v);
      i.url_null = is_null;
      grew = grew || (cap != i.url_value.capacity ());
    }

    // directory
    //
    {
      ::butl::dir_path const& v =
        o.directory;

      // From package-common.hxx:79:14
      ::std::string const& vt =
        (v).string ();

      bool is_null (false);
      std::size_t cap (i.directory_value.capacity ());
      sqlite::value_traits<
          ::std::string,
          sqlite::id_text >::set_image (
        i.directory_value,
        i.directory_size,
        is_null,
        vt);
      i.directory_null = is_null;
      grew = grew || (cap != i.directory_value.capacity ());
    }

    // session
    //
    {
      ::std::string const& v =
        o.session;

      bool is_null (false);
      std::size_t cap (i.session_value.capacity ());
      sqlite::value_traits<
          ::std::string,
          sqlite::id_text >::set_image (
        i.session_value,
        i.session_size,
        is_null,
        v);
      i.session_null = is_null;
      grew = grew || (cap != i.session_value.capacity ());
    }

    // access_time
    //
    {
      ::butl::timestamp const& v =
        o.access_time;

      // From package-common.hxx:102:14
      ::uint64_t const& vt =
        std::chrono::duration_cast < std::chrono::nanoseconds > ((v).time_since_epoch ()).count ();

      bool is_null (false);
      sqlite::value_traits<
          ::uint64_t,
          sqlite::id_integer >::set_image (
        i.access_time_value,
        is_null,
        vt);
      i.access_time_null = is_null;
    }

    // repositories_path
    //
    {
      ::butl::path const& v =
        o.repositories_path;

      // From package-common.hxx:72:14
      ::std::string const& vt =
        (v).representation ();

      bool is_null (false);
      std::size_t cap (i.repositories_path_value.capacity ());
      sqlite::value_traits<
          ::std::string,
          sqlite::id_text >::set_image (
        i.repositories_path_value,
        i.repositories_path_size,
        is_null,
        vt);
      i.repositories_path_null = is_null;
      grew = grew || (cap != i.repositories_path_value.capacity ());
    }

    // repositories_checksum
    //
    {
      ::std::string const& v =
        o.repositories_checksum;

      bool is_null (false);
      std::size_t cap (i.repositories_checksum_value.capacity ());
      sqlite::value_traits<
          ::std::string,
          sqlite::id_text >::set_image (
        i.repositories_checksum_value,
        i.repositories_checksum_size,
        is_null,
        v);
      i.repositories_checksum_null = is_null;
      grew = grew || (cap != i.repositories_checksum_value.capacity ());
    }

    // packages_path
    //
    {
      ::butl::path const& v =
        o.packages_path;

      // From package-common.hxx:72:14
      ::std::string const& vt =
        (v).representation ();

      bool is_null (false);
      std::size_t cap (i.packages_path_value.capacity ());
      sqlite::value_traits<
          ::std::string,
          sqlite::id_text >::set_image (
        i.packages_path_value,
        i.packages_path_size,
        is_null,
        vt);
      i.packages_path_null = is_null;
      grew = grew || (cap != i.packages_path_value.capacity ());
    }

    // packages_checksum
    //
    {
      ::std::string const& v =
        o.packages_checksum;

      bool is_null (false);
      std::size_t cap (i.packages_checksum_value.capacity ());
      sqlite::value_traits<
          ::std::string,
          sqlite::id_text >::set_image (
        i.packages_checksum_value,
        i.packages_checksum_size,
        is_null,
        v);
      i.packages_checksum_null = is_null;
      grew = grew || (cap != i.packages_checksum_value.capacity ());
    }

    return grew;
  }

  void access::object_traits_impl< ::bpkg::pkg_repository_metadata, id_sqlite >::
  init (object_type& o,
        const image_type& i,
        database* db)
  {
    ODB_POTENTIALLY_UNUSED (o);
    ODB_POTENTIALLY_UNUSED (i);
    ODB_POTENTIALLY_UNUSED (db);

    // url
    //
    {
      ::bpkg::repository_url& v =
        o.url;

      sqlite::value_traits<
          ::bpkg::repository_url,
          sqlite::id_text >::set_value (
        v,
        i.url_value,
        i.url_size,
        i.url_null);
    }

    // directory
    //
    {
      ::butl::dir_path& v =
        o.directory;

      ::std::string vt;

      sqlite::value_traits<
          ::std::string,
          sqlite::id_text >::set_value (
        vt,
        i.directory_value,
        i.directory_size,
        i.directory_null);

      // From package-common.hxx:79:14
      v = bpkg::dir_path (vt);
    }

    // session
    //
    {
      ::std::string& v =
        o.session;

      sqlite::value_traits<
          ::std::string,
          sqlite::id_text >::set_value (
        v,
        i.session_value,
        i.session_size,
        i.session_null);
    }

    // access_time
    //
    {
      ::butl::timestamp& v =
        o.access_time;

      ::uint64_t vt;

      sqlite::value_traits<
          ::uint64_t,
          sqlite::id_integer >::set_value (
        vt,
        i.access_time_value,
        i.access_time_null);

      // From package-common.hxx:102:14
      v = butl::timestamp (std::chrono::duration_cast < butl::timestamp::duration > (std::chrono::nanoseconds (vt)));
    }

    // repositories_path
    //
    {
      ::butl::path& v =
        o.repositories_path;

      ::std::string vt;

      sqlite::value_traits<
          ::std::string,
          sqlite::id_text >::set_value (
        vt,
        i.repositories_path_value,
        i.repositories_path_size,
        i.repositories_path_null);

      // From package-common.hxx:72:14
      v = bpkg::path (vt);
    }

    // repositories_checksum
    //
    {
      ::std::string& v =
        o.repositories_checksum;

      sqlite::value_traits<
          ::std::string,
          sqlite::id_text >::set_value (
        v,
        i.repositories_checksum_value,
        i.repositories_checksum_size,
        i.repositories_checksum_null);
    }

    // packages_path
    //
    {
      ::butl::path& v =
        o.packages_path;

      ::std::string vt;

      sqlite::value_traits<
          ::std::string,
          sqlite::id_text >::set_value (
        vt,
        i.packages_path_value,
        i.packages_path_size,
        i.packages_path_null);

      // From package-common.hxx:72:14
      v = bpkg::path (vt);
    }

    // packages_checksum
    //
    {
      ::std::string& v =
        o.packages_checksum;

      sqlite::value_traits<
          ::std::string,
          sqlite::id_text >::set_value (
        v,
        i.packages_checksum_value,
        i.packages_checksum_size,
        i.packages_checksum_null);
    }
  }

  void access::object_traits_impl< ::bpkg::pkg_repository_metadata, id_sqlite >::
  init (id_image_type& i, const id_type& id)
  {
    bool grew (false);
    {
      bool is_null (false);
      std::size_t cap (i.id_value.capacity ());
      sqlite::value_traits<
          ::bpkg::repository_url,
          sqlite::id_text >::set_image (
        i.id_value,
        i.id_size,
        is_null,
        id);
      i.id_null = is_null;
      grew = grew || (cap != i.id_value.capacity ());
    }

    if (grew)
      i.version++;
  }

  const char access::object_traits_impl< ::bpkg::pkg_repository_metadata, id_sqlite >::persist_statement[] =
  "INSERT INTO \"pkg_repository_metadata\" "
  "(\"url\", "
  "\"directory\", "
  "\"session\", "
  "\"access_time\", "
  "\"repositories_path\", "
  "\"repositories_checksum\", "
  "\"packages_path\", "
  "\"packages_checksum\") "
  "VALUES "
  "(?, ?, ?, ?, ?, ?, ?, ?)";

  const char access::object_traits_impl< ::bpkg::pkg_repository_metadata, id_sqlite >::find_statement[] =
  "SELECT "
  "\"pkg_repository_metadata\".\"url\", "
  "\"pkg_repository_metadata\".\"directory\", "
  "\"pkg_repository_metadata\".\"session\", "
  "\"pkg_repository_metadata\".\"access_time\", "
  "\"pkg_repository_metadata\".\"repositories_path\", "
  "\"pkg_repository_metadata\".\"repositories_checksum\", "
  "\"pkg_repository_metadata\".\"packages_path\", "
  "\"pkg_repository_metadata\".\"packages_checksum\" "
  "FROM \"pkg_repository_metadata\" "
  "WHERE \"pkg_repository_metadata\".\"url\"=?";

  const char access::object_traits_impl< ::bpkg::pkg_repository_metadata, id_sqlite >::update_statement[] =
  "UPDATE \"pkg_repository_metadata\" "
  "SET "
  "\"directory\"=?, "
  "\"session\"=?, "
  "\"access_time\"=?, "
  "\"repositories_path\"=?, "
  "\"repositories_checksum\"=?, "
  "\"packages_path\"=?, "
  "\"packages_checksum\"=? "
  "WHERE \"url\"=?";

  const char access::object_traits_impl< ::bpkg::pkg_repository_metadata, id_sqlite >::erase_statement[] =
  "DELETE FROM \"pkg_repository_metadata\" "
  "WHERE \"url\"=?";

  const char access::object_traits_impl< ::bpkg::pkg_repository_metadata, id_sqlite >::query_statement[] =
  "SELECT "
  "\"pkg_repository_metadata\".\"url\", "
  "\"pkg_repository_metadata\".\"directory\", "
  "\"pkg_repository_metadata\".\"session\", "
  "\"pkg_repository_metadata\".\"access_time\", "
  "\"pkg_repository_metadata\".\"repositories_path\", "
  "\"pkg_repository_metadata\".\"repositories_checksum\", "
  "\"pkg_repository_metadata\".\"packages_path\", "
  "\"pkg_repository_metadata\".\"packages_checksum\" "
  "FROM \"pkg_repository_metadata\"";

  const char access::object_traits_impl< ::bpkg::pkg_repository_metadata, id_sqlite >::erase_query_statement[] =
  "DELETE FROM \"pkg_repository_metadata\"";

  const char access::object_traits_impl< ::bpkg::pkg_repository_metadata, id_sqlite >::table_name[] =
  "\"pkg_repository_metadata\"";

  void access::object_traits_impl< ::bpkg::pkg_repository_metadata, id_sqlite >::
  persist (database& db, const object_type& obj)
  {
    using namespace sqlite;

    sqlite::connection& conn (
      sqlite::transaction::current ().connection (db));
    statements_type& sts (
      conn.statement_cache ().find_object<object_type> ());

    callback (db,
              obj,
              callback_event::pre_persist);

    image_type& im (sts.image ());
    binding& imb (sts.insert_image_binding ());

    if (init (im, obj, statement_insert))
      im.version++;

    if (im.version != sts.insert_image_version () ||
        imb.version == 0)
    {
      bind (imb.bind, im, statement_insert);
      sts.insert_image_version (im.version);
      imb.version++;
    }

    insert_statement& st (sts.persist_statement ());
    if (!st.execute ())
      throw object_already_persistent ();

    callback (db,
              obj,
              callback_event::post_persist);
  }

  void access::object_traits_impl< ::bpkg::pkg_repository_metadata, id_sqlite >::
  update (database& db, const object_type& obj)
  {
    ODB_POTENTIALLY_UNUSED (db);

    using namespace sqlite;
    using sqlite::update_statement;

    callback (db, obj, callback_event::pre_update);

    sqlite::transaction& tr (sqlite::transaction::current ());
    sqlite::connection& conn (tr.connection (db));
    statements_type& sts (
      conn.statement_cache ().find_object<object_type> ());

    id_image_type& idi (sts.id_image ());
    init (idi, id (obj));

    image_type& im (sts.image ());
    if (init (im, obj, statement_update))
      im.version++;

    bool u (false);
    binding& imb (sts.update_image_binding ());
    if (im.version != sts.update_image_version () ||
        imb.version == 0)
    {
      bind (imb.bind, im, statement_update);
      sts.update_image_version (im.version);
      imb.version++;
      u = true;
    }

    binding& idb (sts.id_image_binding ());
    if (idi.version != sts.update_id_image_version () ||
        idb.version == 0)
    {
      if (idi.version != sts.id_image_version () ||
          idb.version == 0)
      {
        bind (idb.bind, idi);
        sts.id_image_version (idi.version);
        idb.version++;
      }

      sts.update_id_image_version (idi.version);

      if (!u)
        imb.version++;
    }

    update_statement& st (sts.update_statement ());
    if (st.execute () == 0)
      throw object_not_persistent ();

    callback (db, obj, callback_event::post_update);
    pointer_cache_traits::update (db, obj);
  }

  void access::object_traits_impl< ::bpkg::pkg_repository_metadata, id_sqlite >::
  erase (database& db, const id_type& id)
  {
    using namespace sqlite;

    sqlite::connection& conn (
      sqlite::transaction::current ().connection (db));
    statements_type& sts (
      conn.statement_cache ().find_object<object_type> ());

    id_image_type& i (sts.id_image ());
    init (i, id);

    binding& idb (sts.id_image_binding ());
    if (i.version != sts.id_image_version () || idb.version == 0)
    {
      bind (idb.bind, i);
      sts.id_image_version (i.version);
      idb.version++;
    }

    if (sts.erase_statement ().execute () != 1)
      throw object_not_persistent ();

    pointer_cache_traits::erase (db, id);
  }

  access::object_traits_impl< ::bpkg::pkg_repository_metadata, id_sqlite >::pointer_type
  access::object_traits_impl< ::bpkg::pkg_repository_metadata, id_sqlite >::
  find (database& db, const id_type& id)
  {
    using namespace sqlite;

    {
      pointer_type p (pointer_cache_traits::find (db, id));

      if (!pointer_traits::null_ptr (p))
        return p;
    }

    sqlite::connection& conn (
      sqlite::transaction::current ().connection (db));
    statements_type& sts (
      conn.statement_cache ().find_object<object_type> ());

    statements_type::auto_lock l (sts);

    if (l.locked ())
    {
      if (!find_ (sts, &id))
        return pointer_type ();
    }

    pointer_type p (
      access::object_factory<object_type, pointer_type>::create ());
    pointer_traits::guard pg (p);

    pointer_cache_traits::insert_guard ig (
      pointer_cache_traits::insert (db, id, p));

    object_type& obj (pointer_traits::get_ref (p));

    if (l.locked ())
    {
      select_statement& st (sts.find_statement ());
      ODB_POTENTIALLY_UNUSED (st);

      callback (db, obj, callback_event::pre_load);
      init (obj, sts.image (), &db);
      load_ (sts, obj, false);
      sts.load_delayed (0);
      l.unlock ();
      callback (db, obj, callback_event::post_load);
      pointer_cache_traits::load (ig.position ());
    }
    else
      sts.delay_load (id, obj, ig.position ());

    ig.release ();
    pg.release ();
    return p;
  }

  bool access::object_traits_impl< ::bpkg::pkg_repository_metadata, id_sqlite >::
  find (database& db, const id_type& id, object_type& obj)
  {
    using namespace sqlite;

    sqlite::connection& conn (
      sqlite::transaction::current ().connection (db));
    statements_type& sts (
      conn.statement_cache ().find_object<object_type> ());

    statements_type::auto_lock l (sts);
    assert (l.locked ()) /* Must be a top-level call. */;

    if (!find_ (sts, &id))
      return false;

    select_statement& st (sts.find_statement ());
    ODB_POTENTIALLY_UNUSED (st);

    reference_cache_traits::position_type pos (
      reference_cache_traits::insert (db, id, obj));
    reference_cache_traits::insert_guard ig (pos);

    callback (db, obj, callback_event::pre_load);
    init (obj, sts.image (), &db);
    load_ (sts, obj, false);
    sts.load_delayed (0);
    l.unlock ();
    callback (db, obj, callback_event::post_load);
    reference_cache_traits::load (pos);
    ig.release ();
    return true;
  }

  bool access::object_traits_impl< ::bpkg::pkg_repository_metadata, id_sqlite >::
  reload (database& db, object_type& obj)
  {
    using namespace sqlite;

    sqlite::connection& conn (
      sqlite::transaction::current ().connection (db));
    statements_type& sts (
      conn.statement_cache ().find_object<object_type> ());

    statements_type::auto_lock l (sts);
    assert (l.locked ()) /* Must be a top-level call. */;

    const id_type& id (object_traits_impl::id (obj));
    if (!find_ (sts, &id))
      return false;

    select_statement& st (sts.find_statement ());
    ODB_POTENTIALLY_UNUSED (st);

    callback (db, obj, callback_event::pre_load);
    init (obj, sts.image (), &db);
    load_ (sts, obj, true);
    sts.load_delayed (0);
    l.unlock ();
    callback (db, obj, callback_event::post_load);
    return true;
  }

  bool access::object_traits_impl< ::bpkg::pkg_repository_metadata, id_sqlite >::
  find_ (statements_type& sts,
         const id_type* id)
  {
    using namespace sqlite;

    id_image_type& i (sts.id_image ());
    init (i, *id);

    binding& idb (sts.id_image_binding ());
    if (i.version != sts.id_image_version () || idb.version == 0)
    {
      bind (idb.bind, i);
      sts.id_image_version (i.version);
      idb.version++;
    }

    image_type& im (sts.image ());
    binding& imb (sts.select_image_binding ());

    if (im.version != sts.select_image_version () ||
        imb.version == 0)
    {
      bind (imb.bind, im, statement_select);
      sts.select_image_version (im.version);
      imb.version++;
    }

    select_statement& st (sts.find_statement ());

    st.execute ();
    auto_result ar (st);
    select_statement::result r (st.fetch ());

    if (r == select_statement::truncated)
    {
      if (grow (im, sts.select_image_truncated ()))
        im.version++;

      if (im.version != sts.select_image_version ())
      {
        bind (imb.bind, im, statement_select);
        sts.select_image_version (im.version);
        imb.version++;
        st.refetch ();
      }
    }

    return r != select_statement::no_data;
  }

  result< access::object_traits_impl< ::bpkg::pkg_repository_metadata, id_sqlite >::object_type >
  access::object_traits_impl< ::bpkg::pkg_repository_metadata, id_sqlite >::
  query (database& db, const query_base_type& q)
  {
    using namespace sqlite;
    using odb::details::shared;
    using odb::details::shared_ptr;

    sqlite::connection& conn (
      sqlite::transaction::current ().connection (db));

    statements_type& sts (
      conn.statement_cache ().find_object<object_type> ());

    image_type& im (sts.image ());
    binding& imb (sts.select_image_binding ());

    if (im.version != sts.select_image_version () ||
        imb.version == 0)
    {
      bind (imb.bind, im, statement_select);
      sts.select_image_version (im.version);
      imb.version++;
    }

    std::string text (query_statement);
    if (!q.empty ())
    {
      text += " ";
      text += q.clause ();
    }

    q.init_parameters ();
    shared_ptr<select_statement> st (
      new (shared) select_statement (
        conn,
        text,
        false,
        true,
        q.parameters_binding (),
        imb));

    st->execute ();

    shared_ptr< odb::object_result_impl<object_type> > r (
      new (shared) sqlite::object_result_impl<object_type> (
        q, st, sts, 0));

    return result<object_type> (r);
  }

  unsigned long long access::object_traits_impl< ::bpkg::pkg_repository_metadata, id_sqlite >::
  erase_query (database& db, const query_base_type& q)
  {
    using namespace sqlite;

    sqlite::connection& conn (
      sqlite::transaction::current ().connection (db));

    std::string text (erase_query_statement);
    if (!q.empty ())
    {
      text += ' ';
      text += q.clause ();
    }

    q.init_parameters ();
    delete_statement st (
      conn,
      text,
      q.parameters_binding ());

    return st.execute ();
  }

  // pkg_repository_package
  //

  struct access::object_traits_impl< ::bpkg::pkg_repository_package, id_sqlite >::extra_statement_cache_type
  {
    extra_statement_cache_type (
      sqlite::connection&,
      image_type&,
      id_image_type&,
      sqlite::binding&,
      sqlite::binding&)
    {
    }
  };

  access::object_traits_impl< ::bpkg::pkg_repository_package, id_sqlite >::id_type
  access::object_traits_impl< ::bpkg::pkg_repository_package, id_sqlite >::
  id (const image_type& i)
  {
    sqlite::database* db (0);
    ODB_POTENTIALLY_UNUSED (db);

    id_type id;
    {
      composite_value_traits< ::bpkg::package_id, id_sqlite >::init (
        id,
        i.id_value,
        db);
    }

    return id;
  }

  bool access::object_traits_impl< ::bpkg::pkg_repository_package, id_sqlite >::
  grow (image_type& i,
        bool* t)
  {
    ODB_POTENTIALLY_UNUSED (i);
    ODB_POTENTIALLY_UNUSED (t);

    bool grew (false);

    // id
    //
    if (composite_value_traits< ::bpkg::package_id, id_sqlite >::grow (
          i.id_value, t + 0UL))
      grew = true;

    // version
    //
    if (composite_value_traits< ::bpkg::original_version, id_sqlite >::grow (
          i.version_value, t + 6UL))
      grew = true;

    // access_time
    //
    t[8UL] = false;

    // archive
    //
    if (t[9UL])
    {
      i.archive_value.capacity (i.archive_size);
      grew = true;
    }

    // checksum
    //
    if (t[10UL])
    {
      i.checksum_value.capacity (i.checksum_size);
      grew = true;
    }

    // repository
    //
    if (t[11UL])
    {
      i.repository_value.capacity (i.repository_size);
      grew = true;
    }

    return grew;
  }

  void access::object_traits_impl< ::bpkg::pkg_repository_package, id_sqlite >::
  bind (sqlite::bind* b,
        image_type& i,
        sqlite::statement_kind sk)
  {
    ODB_POTENTIALLY_UNUSED (sk);

    using namespace sqlite;

    std::size_t n (0);

    // id
    //
    if (sk != statement_update)
    {
      composite_value_traits< ::bpkg::package_id, id_sqlite >::bind (
        b + n, i.id_value, sk);
      n += 6UL;
    }

    // version
    //
    composite_value_traits< ::bpkg::original_version, id_sqlite >::bind (
      b + n, i.version_value, sk);
    n += 2UL;

    // access_time
    //
    b[n].type = sqlite::bind::integer;
    b[n].buffer = &i.access_time_value;
    b[n].is_null = &i.access_time_null;
    n++;

    // archive
    //
    b[n].type = sqlite::image_traits<
      ::std::string,
      sqlite::id_text>::bind_value;
    b[n].buffer = i.archive_value.data ();
    b[n].size = &i.archive_size;
    b[n].capacity = i.archive_value.capacity ();
    b[n].is_null = &i.archive_null;
    n++;

    // checksum
    //
    b[n].type = sqlite::image_traits<
      ::std::string,
      sqlite::id_text>::bind_value;
    b[n].buffer = i.checksum_value.data ();
    b[n].size = &i.checksum_size;
    b[n].capacity = i.checksum_value.capacity ();
    b[n].is_null = &i.checksum_null;
    n++;

    // repository
    //
    b[n].type = sqlite::image_traits<
      ::bpkg::repository_url,
      sqlite::id_text>::bind_value;
    b[n].buffer = i.repository_value.data ();
    b[n].size = &i.repository_size;
    b[n].capacity = i.repository_value.capacity ();
    b[n].is_null = &i.repository_null;
    n++;
  }

  void access::object_traits_impl< ::bpkg::pkg_repository_package, id_sqlite >::
  bind (sqlite::bind* b, id_image_type& i)
  {
    std::size_t n (0);
    sqlite::statement_kind sk (sqlite::statement_select);
    composite_value_traits< ::bpkg::package_id, id_sqlite >::bind (
      b + n, i.id_value, sk);
  }

  bool access::object_traits_impl< ::bpkg::pkg_repository_package, id_sqlite >::
  init (image_type& i,
        const object_type& o,
        sqlite::statement_kind sk)
  {
    ODB_POTENTIALLY_UNUSED (i);
    ODB_POTENTIALLY_UNUSED (o);
    ODB_POTENTIALLY_UNUSED (sk);

    using namespace sqlite;

    bool grew (false);

    // id
    //
    if (sk == statement_insert)
    {
      ::bpkg::package_id const& v =
        o.id;

      if (composite_value_traits< ::bpkg::package_id, id_sqlite >::init (
            i.id_value,
            v,
            sk))
        grew = true;
    }

    // version
    //
    {
      ::bpkg::original_version const& v =
        o.version;

      if (composite_value_traits< ::bpkg::original_version, id_sqlite >::init (
            i.version_value,
            v,
            sk))
        grew = true;
    }

    // access_time
    //
    {
      ::butl::timestamp const& v =
        o.access_time;

      // From package-common.hxx:102:14
      ::uint64_t const& vt =
        std::chrono::duration_cast < std::chrono::nanoseconds > ((v).time_since_epoch ()).count ();

      bool is_null (false);
      sqlite::value_traits<
          ::uint64_t,
          sqlite::id_integer >::set_image (
        i.access_time_value,
        is_null,
        vt);
      i.access_time_null = is_null;
    }

    // archive
    //
    {
      ::butl::path const& v =
        o.archive;

      // From package-common.hxx:72:14
      ::std::string const& vt =
        (v).representation ();

      bool is_null (false);
      std::size_t cap (i.archive_value.capacity ());
      sqlite::value_traits<
          ::std::string,
          sqlite::id_text >::set_image (
        i.archive_value,
        i.archive_size,
        is_null,
        vt);
      i.archive_null = is_null;
      grew = grew || (cap != i.archive_value.capacity ());
    }

    // checksum
    //
    {
      ::std::string const& v =
        o.checksum;

      bool is_null (false);
      std::size_t cap (i.checksum_value.capacity ());
      sqlite::value_traits<
          ::std::string,
          sqlite::id_text >::set_image (
        i.checksum_value,
        i.checksum_size,
        is_null,
        v);
      i.checksum_null = is_null;
      grew = grew || (cap != i.checksum_value.capacity ());
    }

    // repository
    //
    {
      ::bpkg::repository_url const& v =
        o.repository;

      bool is_null (false);
      std::size_t cap (i.repository_value.capacity ());
      sqlite::value_traits<
          ::bpkg::repository_url,
          sqlite::id_text >::set_image (
        i.repository_value,
        i.repository_size,
        is_null,
        v);
      i.repository_null = is_null;
      grew = grew || (cap != i.repository_value.capacity ());
    }

    return grew;
  }

  void access::object_traits_impl< ::bpkg::pkg_repository_package, id_sqlite >::
  init (object_type& o,
        const image_type& i,
        database* db)
  {
    ODB_POTENTIALLY_UNUSED (o);
    ODB_POTENTIALLY_UNUSED (i);
    ODB_POTENTIALLY_UNUSED (db);

    // id
    //
    {
      ::bpkg::package_id& v =
        o.id;

      composite_value_traits< ::bpkg::package_id, id_sqlite >::init (
        v,
        i.id_value,
        db);
    }

    // version
    //
    {
      // From fetch-cache-data.hxx:170:32
      ::bpkg::original_version v;

      composite_value_traits< ::bpkg::original_version, id_sqlite >::init (
        v,
        i.version_value,
        db);

      // From fetch-cache-data.hxx:170:32
      o.version.init (o.id.version, (v));
    }

    // access_time
    //
    {
      ::butl::timestamp& v =
        o.access_time;

      ::uint64_t vt;

      sqlite::value_traits<
          ::uint64_t,
          sqlite::id_integer >::set_value (
        vt,
        i.access_time_value,
        i.access_time_null);

      // From package-common.hxx:102:14
      v = butl::timestamp (std::chrono::duration_cast < butl::timestamp::duration > (std::chrono::nanoseconds (vt)));
    }

    // archive
    //
    {
      ::butl::path& v =
        o.archive;

      ::std::string vt;

      sqlite::value_traits<
          ::std::string,
          sqlite::id_text >::set_value (
        vt,
        i.archive_value,
        i.archive_size,
        i.archive_null);

      // From package-common.hxx:72:14
      v = bpkg::path (vt);
    }

    // checksum
    //
    {
      ::std::string& v =
        o.checksum;

      sqlite::value_traits<
          ::std::string,
          sqlite::id_text >::set_value (
        v,
        i.checksum_value,
        i.checksum_size,
        i.checksum_null);
    }

    // repository
    //
    {
      ::bpkg::repository_url& v =
        o.repository;

      sqlite::value_traits<
          ::bpkg::repository_url,
          sqlite::id_text >::set_value (
        v,
        i.repository_value,
        i.repository_size,
        i.repository_null);
    }
  }

  void access::object_traits_impl< ::bpkg::pkg_repository_package, id_sqlite >::
  init (id_image_type& i, const id_type& id)
  {
    bool grew (false);
    sqlite::statement_kind sk (sqlite::statement_select);
    {
      if (composite_value_traits< ::bpkg::package_id, id_sqlite >::init (
            i.id_value,
            id,
            sk))
        grew = true;
    }

    if (grew)
      i.version++;
  }

  const char access::object_traits_impl< ::bpkg::pkg_repository_package, id_sqlite >::persist_statement[] =
  "INSERT INTO \"pkg_repository_package\" "
  "(\"name\", "
  "\"version_epoch\", "
  "\"version_canonical_upstream\", "
  "\"version_canonical_release\", "
  "\"version_revision\", "
  "\"version_iteration\", "
  "\"version_upstream\", "
  "\"version_release\", "
  "\"access_time\", "
  "\"archive\", "
  "\"checksum\", "
  "\"repository\") "
  "VALUES "
  "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";

  const char access::object_traits_impl< ::bpkg::pkg_repository_package, id_sqlite >::find_statement[] =
  "SELECT "
  "\"pkg_repository_package\".\"name\", "
  "\"pkg_repository_package\".\"version_epoch\", "
  "\"pkg_repository_package\".\"version_canonical_upstream\", "
  "\"pkg_repository_package\".\"version_canonical_release\", "
  "\"pkg_repository_package\".\"version_revision\", "
  "\"pkg_repository_package\".\"version_iteration\", "
  "\"pkg_repository_package\".\"version_upstream\", "
  "\"pkg_repository_package\".\"version_release\", "
  "\"pkg_repository_package\".\"access_time\", "
  "\"pkg_repository_package\".\"archive\", "
  "\"pkg_repository_package\".\"checksum\", "
  "\"pkg_repository_package\".\"repository\" "
  "FROM \"pkg_repository_package\" "
  "WHERE \"pkg_repository_package\".\"name\"=? AND \"pkg_repository_package\".\"version_epoch\"=? AND \"pkg_repository_package\".\"version_canonical_upstream\"=? AND \"pkg_repository_package\".\"version_canonical_release\"=? AND \"pkg_repository_package\".\"version_revision\"=? AND \"pkg_repository_package\".\"version_iteration\"=?";

  const char access::object_traits_impl< ::bpkg::pkg_repository_package, id_sqlite >::update_statement[] =
  "UPDATE \"pkg_repository_package\" "
  "SET "
  "\"version_upstream\"=?, "
  "\"version_release\"=?, "
  "\"access_time\"=?, "
  "\"archive\"=?, "
  "\"checksum\"=?, "
  "\"repository\"=? "
  "WHERE \"name\"=? AND \"version_epoch\"=? AND \"version_canonical_upstream\"=? AND \"version_canonical_release\"=? AND \"version_revision\"=? AND \"version_iteration\"=?";

  const char access::object_traits_impl< ::bpkg::pkg_repository_package, id_sqlite >::erase_statement[] =
  "DELETE FROM \"pkg_repository_package\" "
  "WHERE \"name\"=? AND \"version_epoch\"=? AND \"version_canonical_upstream\"=? AND \"version_canonical_release\"=? AND \"version_revision\"=? AND \"version_iteration\"=?";

  const char access::object_traits_impl< ::bpkg::pkg_repository_package, id_sqlite >::query_statement[] =
  "SELECT "
  "\"pkg_repository_package\".\"name\", "
  "\"pkg_repository_package\".\"version_epoch\", "
  "\"pkg_repository_package\".\"version_canonical_upstream\", "
  "\"pkg_repository_package\".\"version_canonical_release\", "
  "\"pkg_repository_package\".\"version_revision\", "
  "\"pkg_repository_package\".\"version_iteration\", "
  "\"pkg_repository_package\".\"version_upstream\", "
  "\"pkg_repository_package\".\"version_release\", "
  "\"pkg_repository_package\".\"access_time\", "
  "\"pkg_repository_package\".\"archive\", "
  "\"pkg_repository_package\".\"checksum\", "
  "\"pkg_repository_package\".\"repository\" "
  "FROM \"pkg_repository_package\"";

  const char access::object_traits_impl< ::bpkg::pkg_repository_package, id_sqlite >::erase_query_statement[] =
  "DELETE FROM \"pkg_repository_package\"";

  const char access::object_traits_impl< ::bpkg::pkg_repository_package, id_sqlite >::table_name[] =
  "\"pkg_repository_package\"";

  void access::object_traits_impl< ::bpkg::pkg_repository_package, id_sqlite >::
  persist (database& db, const object_type& obj)
  {
    using namespace sqlite;

    sqlite::connection& conn (
      sqlite::transaction::current ().connection (db));
    statements_type& sts (
      conn.statement_cache ().find_object<object_type> ());

    callback (db,
              obj,
              callback_event::pre_persist);

    image_type& im (sts.image ());
    binding& imb (sts.insert_image_binding ());

    if (init (im, obj, statement_insert))
      im.version++;

    if (im.version != sts.insert_image_version () ||
        imb.version == 0)
    {
      bind (imb.bind, im, statement_insert);
      sts.insert_image_version (im.version);
      imb.version++;
    }

    insert_statement& st (sts.persist_statement ());
    if (!st.execute ())
      throw object_already_persistent ();

    callback (db,
              obj,
              callback_event::post_persist);
  }

  void access::object_traits_impl< ::bpkg::pkg_repository_package, id_sqlite >::
  update (database& db, const object_type& obj)
  {
    ODB_POTENTIALLY_UNUSED (db);

    using namespace sqlite;
    using sqlite::update_statement;

    callback (db, obj, callback_event::pre_update);

    sqlite::transaction& tr (sqlite::transaction::current ());
    sqlite::connection& conn (tr.connection (db));
    statements_type& sts (
      conn.statement_cache ().find_object<object_type> ());

    id_image_type& idi (sts.id_image ());
    init (idi, id (obj));

    image_type& im (sts.image ());
    if (init (im, obj, statement_update))
      im.version++;

    bool u (false);
    binding& imb (sts.update_image_binding ());
    if (im.version != sts.update_image_version () ||
        imb.version == 0)
    {
      bind (imb.bind, im, statement_update);
      sts.update_image_version (im.version);
      imb.version++;
      u = true;
    }

    binding& idb (sts.id_image_binding ());
    if (idi.version != sts.update_id_image_version () ||
        idb.version == 0)
    {
      if (idi.version != sts.id_image_version () ||
          idb.version == 0)
      {
        bind (idb.bind, idi);
        sts.id_image_version (idi.version);
        idb.version++;
      }

      sts.update_id_image_version (idi.version);

      if (!u)
        imb.version++;
    }

    update_statement& st (sts.update_statement ());
    if (st.execute () == 0)
      throw object_not_persistent ();

    callback (db, obj, callback_event::post_update);
    pointer_cache_traits::update (db, obj);
  }

  void access::object_traits_impl< ::bpkg::pkg_repository_package, id_sqlite >::
  erase (database& db, const id_type& id)
  {
    using namespace sqlite;

    sqlite::connection& conn (
      sqlite::transaction::current ().connection (db));
    statements_type& sts (
      conn.statement_cache ().find_object<object_type> ());

    id_image_type& i (sts.id_image ());
    init (i, id);

    binding& idb (sts.id_image_binding ());
    if (i.version != sts.id_image_version () || idb.version == 0)
    {
      bind (idb.bind, i);
      sts.id_image_version (i.version);
      idb.version++;
    }

    if (sts.erase_statement ().execute () != 1)
      throw object_not_persistent ();

    pointer_cache_traits::erase (db, id);
  }

  access::object_traits_impl< ::bpkg::pkg_repository_package, id_sqlite >::pointer_type
  access::object_traits_impl< ::bpkg::pkg_repository_package, id_sqlite >::
  find (database& db, const id_type& id)
  {
    using namespace sqlite;

    {
      pointer_type p (pointer_cache_traits::find (db, id));

      if (!pointer_traits::null_ptr (p))
        return p;
    }

    sqlite::connection& conn (
      sqlite::transaction::current ().connection (db));
    statements_type& sts (
      conn.statement_cache ().find_object<object_type> ());

    statements_type::auto_lock l (sts);

    if (l.locked ())
    {
      if (!find_ (sts, &id))
        return pointer_type ();
    }

    pointer_type p (
      access::object_factory<object_type, pointer_type>::create ());
    pointer_traits::guard pg (p);

    pointer_cache_traits::insert_guard ig (
      pointer_cache_traits::insert (db, id, p));

    object_type& obj (pointer_traits::get_ref (p));

    if (l.locked ())
    {
      select_statement& st (sts.find_statement ());
      ODB_POTENTIALLY_UNUSED (st);

      callback (db, obj, callback_event::pre_load);
      init (obj, sts.image (), &db);
      load_ (sts, obj, false);
      sts.load_delayed (0);
      l.unlock ();
      callback (db, obj, callback_event::post_load);
      pointer_cache_traits::load (ig.position ());
    }
    else
      sts.delay_load (id, obj, ig.position ());

    ig.release ();
    pg.release ();
    return p;
  }

  bool access::object_traits_impl< ::bpkg::pkg_repository_package, id_sqlite >::
  find (database& db, const id_type& id, object_type& obj)
  {
    using namespace sqlite;

    sqlite::connection& conn (
      sqlite::transaction::current ().connection (db));
    statements_type& sts (
      conn.statement_cache ().find_object<object_type> ());

    statements_type::auto_lock l (sts);
    assert (l.locked ()) /* Must be a top-level call. */;

    if (!find_ (sts, &id))
      return false;

    select_statement& st (sts.find_statement ());
    ODB_POTENTIALLY_UNUSED (st);

    reference_cache_traits::position_type pos (
      reference_cache_traits::insert (db, id, obj));
    reference_cache_traits::insert_guard ig (pos);

    callback (db, obj, callback_event::pre_load);
    init (obj, sts.image (), &db);
    load_ (sts, obj, false);
    sts.load_delayed (0);
    l.unlock ();
    callback (db, obj, callback_event::post_load);
    reference_cache_traits::load (pos);
    ig.release ();
    return true;
  }

  bool access::object_traits_impl< ::bpkg::pkg_repository_package, id_sqlite >::
  reload (database& db, object_type& obj)
  {
    using namespace sqlite;

    sqlite::connection& conn (
      sqlite::transaction::current ().connection (db));
    statements_type& sts (
      conn.statement_cache ().find_object<object_type> ());

    statements_type::auto_lock l (sts);
    assert (l.locked ()) /* Must be a top-level call. */;

    const id_type& id (object_traits_impl::id (obj));
    if (!find_ (sts, &id))
      return false;

    select_statement& st (sts.find_statement ());
    ODB_POTENTIALLY_UNUSED (st);

    callback (db, obj, callback_event::pre_load);
    init (obj, sts.image (), &db);
    load_ (sts, obj, true);
    sts.load_delayed (0);
    l.unlock ();
    callback (db, obj, callback_event::post_load);
    return true;
  }

  bool access::object_traits_impl< ::bpkg::pkg_repository_package, id_sqlite >::
  find_ (statements_type& sts,
         const id_type* id)
  {
    using namespace sqlite;

    id_image_type& i (sts.id_image ());
    init (i, *id);

    binding& idb (sts.id_image_binding ());
    if (i.version != sts.id_image_version () || idb.version == 0)
    {
      bind (idb.bind, i);
      sts.id_image_version (i.version);
      idb.version++;
    }

    image_type& im (sts.image ());
    binding& imb (sts.select_image_binding ());

    if (im.version != sts.select_image_version () ||
        imb.version == 0)
    {
      bind (imb.bind, im, statement_select);
      sts.select_image_version (im.version);
      imb.version++;
    }

    select_statement& st (sts.find_statement ());

    st.execute ();
    auto_result ar (st);
    select_statement::result r (st.fetch ());

    if (r == select_statement::truncated)
    {
      if (grow (im, sts.select_image_truncated ()))
        im.version++;

      if (im.version != sts.select_image_version ())
      {
        bind (imb.bind, im, statement_select);
        sts.select_image_version (im.version);
        imb.version++;
        st.refetch ();
      }
    }

    return r != select_statement::no_data;
  }

  result< access::object_traits_impl< ::bpkg::pkg_repository_package, id_sqlite >::object_type >
  access::object_traits_impl< ::bpkg::pkg_repository_package, id_sqlite >::
  query (database& db, const query_base_type& q)
  {
    using namespace sqlite;
    using odb::details::shared;
    using odb::details::shared_ptr;

    sqlite::connection& conn (
      sqlite::transaction::current ().connection (db));

    statements_type& sts (
      conn.statement_cache ().find_object<object_type> ());

    image_type& im (sts.image ());
    binding& imb (sts.select_image_binding ());

    if (im.version != sts.select_image_version () ||
        imb.version == 0)
    {
      bind (imb.bind, im, statement_select);
      sts.select_image_version (im.version);
      imb.version++;
    }

    std::string text (query_statement);
    if (!q.empty ())
    {
      text += " ";
      text += q.clause ();
    }

    q.init_parameters ();
    shared_ptr<select_statement> st (
      new (shared) select_statement (
        conn,
        text,
        false,
        true,
        q.parameters_binding (),
        imb));

    st->execute ();

    shared_ptr< odb::object_result_impl<object_type> > r (
      new (shared) sqlite::object_result_impl<object_type> (
        q, st, sts, 0));

    return result<object_type> (r);
  }

  unsigned long long access::object_traits_impl< ::bpkg::pkg_repository_package, id_sqlite >::
  erase_query (database& db, const query_base_type& q)
  {
    using namespace sqlite;

    sqlite::connection& conn (
      sqlite::transaction::current ().connection (db));

    std::string text (erase_query_statement);
    if (!q.empty ())
    {
      text += ' ';
      text += q.clause ();
    }

    q.init_parameters ();
    delete_statement st (
      conn,
      text,
      q.parameters_binding ());

    return st.execute ();
  }

  // git_repository_state
  //

  struct access::object_traits_impl< ::bpkg::git_repository_state, id_sqlite >::extra_statement_cache_type
  {
    extra_statement_cache_type (
      sqlite::connection&,
      image_type&,
      id_image_type&,
      sqlite::binding&,
      sqlite::binding&)
    {
    }
  };

  access::object_traits_impl< ::bpkg::git_repository_state, id_sqlite >::id_type
  access::object_traits_impl< ::bpkg::git_repository_state, id_sqlite >::
  id (const image_type& i)
  {
    sqlite::database* db (0);
    ODB_POTENTIALLY_UNUSED (db);

    id_type id;
    {
      sqlite::value_traits<
          ::bpkg::repository_url,
          sqlite::id_text >::set_value (
        id,
        i.url_value,
        i.url_size,
        i.url_null);
    }

    return id;
  }

  bool access::object_traits_impl< ::bpkg::git_repository_state, id_sqlite >::
  grow (image_type& i,
        bool* t)
  {
    ODB_POTENTIALLY_UNUSED (i);
    ODB_POTENTIALLY_UNUSED (t);

    bool grew (false);

    // url
    //
    if (t[0UL])
    {
      i.url_value.capacity (i.url_size);
      grew = true;
    }

    // directory
    //
    if (t[1UL])
    {
      i.directory_value.capacity (i.directory_size);
      grew = true;
    }

    // session
    //
    if (t[2UL])
    {
      i.session_value.capacity (i.session_size);
      grew = true;
    }

    // access_time
    //
    t[3UL] = false;

    return grew;
  }

  void access::object_traits_impl< ::bpkg::git_repository_state, id_sqlite >::
  bind (sqlite::bind* b,
        image_type& i,
        sqlite::statement_kind sk)
  {
    ODB_POTENTIALLY_UNUSED (sk);

    using namespace sqlite;

    std::size_t n (0);

    // url
    //
    if (sk != statement_update)
    {
      b[n].type = sqlite::image_traits<
        ::bpkg::repository_url,
        sqlite::id_text>::bind_value;
      b[n].buffer = i.url_value.data ();
      b[n].size = &i.url_size;
      b[n].capacity = i.url_value.capacity ();
      b[n].is_null = &i.url_null;
      n++;
    }

    // directory
    //
    b[n].type = sqlite::image_traits<
      ::std::string,
      sqlite::id_text>::bind_value;
    b[n].buffer = i.directory_value.data ();
    b[n].size = &i.directory_size;
    b[n].capacity = i.directory_value.capacity ();
    b[n].is_null = &i.directory_null;
    n++;

    // session
    //
    b[n].type = sqlite::image_traits<
      ::std::string,
      sqlite::id_text>::bind_value;
    b[n].buffer = i.session_value.data ();
    b[n].size = &i.session_size;
    b[n].capacity = i.session_value.capacity ();
    b[n].is_null = &i.session_null;
    n++;

    // access_time
    //
    b[n].type = sqlite::bind::integer;
    b[n].buffer = &i.access_time_value;
    b[n].is_null = &i.access_time_null;
    n++;
  }

  void access::object_traits_impl< ::bpkg::git_repository_state, id_sqlite >::
  bind (sqlite::bind* b, id_image_type& i)
  {
    std::size_t n (0);
    b[n].type = sqlite::image_traits<
      ::bpkg::repository_url,
      sqlite::id_text>::bind_value;
    b[n].buffer = i.id_value.data ();
    b[n].size = &i.id_size;
    b[n].capacity = i.id_value.capacity ();
    b[n].is_null = &i.id_null;
  }

  bool access::object_traits_impl< ::bpkg::git_repository_state, id_sqlite >::
  init (image_type& i,
        const object_type& o,
        sqlite::statement_kind sk)
  {
    ODB_POTENTIALLY_UNUSED (i);
    ODB_POTENTIALLY_UNUSED (o);
    ODB_POTENTIALLY_UNUSED (sk);

    using namespace sqlite;

    bool grew (false);

    // url
    //
    if (sk == statement_insert)
    {
      ::bpkg::repository_url const& v =
        o.url;

      bool is_null (false);
      std::size_t cap (i.url_value.capacity ());
      sqlite::value_traits<
          ::bpkg::repository_url,
          sqlite::id_text >::set_image (
        i.url_value,
        i.url_size,
        is_null,
        v);
      i.url_null = is_null;
      grew = grew || (cap != i.url_value.capacity ());
    }

    // directory
    //
    {
      ::butl::dir_path const& v =
        o.directory;

      // From package-common.hxx:79:14
      ::std::string const& vt =
        (v).string ();

      bool is_null (false);
      std::size_t cap (i.directory_value.capacity ());
      sqlite::value_traits<
          ::std::string,
          sqlite::id_text >::set_image (
        i.directory_value,
        i.directory_size,
        is_null,
        vt);
      i.directory_null = is_null;
      grew = grew || (cap != i.directory_value.capacity ());
    }

    // session
    //
    {
      ::std::string const& v =
        o.session;

      bool is_null (false);
      std::size_t cap (i.session_value.capacity ());
      sqlite::value_traits<
          ::std::string,
          sqlite::id_text >::set_image (
        i.session_value,
        i.session_size,
        is_null,
        v);
      i.session_null = is_null;
      grew = grew || (cap != i.session_value.capacity ());
    }

    // access_time
    //
    {
      ::butl::timestamp const& v =
        o.access_time;

      // From package-common.hxx:102:14
      ::uint64_t const& vt =
        std::chrono::duration_cast < std::chrono::nanoseconds > ((v).time_since_epoch ()).count ();

      bool is_null (false);
      sqlite::value_traits<
          ::uint64_t,
          sqlite::id_integer >::set_image (
        i.access_time_value,
        is_null,
        vt);
      i.access_time_null = is_null;
    }

    return grew;
  }

  void access::object_traits_impl< ::bpkg::git_repository_state, id_sqlite >::
  init (object_type& o,
        const image_type& i,
        database* db)
  {
    ODB_POTENTIALLY_UNUSED (o);
    ODB_POTENTIALLY_UNUSED (i);
    ODB_POTENTIALLY_UNUSED (db);

    // url
    //
    {
      ::bpkg::repository_url& v =
        o.url;

      sqlite::value_traits<
          ::bpkg::repository_url,
          sqlite::id_text >::set_value (
        v,
        i.url_value,
        i.url_size,
        i.url_null);
    }

    // directory
    //
    {
      ::butl::dir_path& v =
        o.directory;

      ::std::string vt;

      sqlite::value_traits<
          ::std::string,
          sqlite::id_text >::set_value (
        vt,
        i.directory_value,
        i.directory_size,
        i.directory_null);

      // From package-common.hxx:79:14
      v = bpkg::dir_path (vt);
    }

    // session
    //
    {
      ::std::string& v =
        o.session;

      sqlite::value_traits<
          ::std::string,
          sqlite::id_text >::set_value (
        v,
        i.session_value,
        i.session_size,
        i.session_null);
    }

    // access_time
    //
    {
      ::butl::timestamp& v =
        o.access_time;

      ::uint64_t vt;

      sqlite::value_traits<
          ::uint64_t,
          sqlite::id_integer >::set_value (
        vt,
        i.access_time_value,
        i.access_time_null);

      // From package-common.hxx:102:14
      v = butl::timestamp (std::chrono::duration_cast < butl::timestamp::duration > (std::chrono::nanoseconds (vt)));
    }
  }

  void access::object_traits_impl< ::bpkg::git_repository_state, id_sqlite >::
  init (id_image_type& i, const id_type& id)
  {
    bool grew (false);
    {
      bool is_null (false);
      std::size_t cap (i.id_value.capacity ());
      sqlite::value_traits<
          ::bpkg::repository_url,
          sqlite::id_text >::set_image (
        i.id_value,
        i.id_size,
        is_null,
        id);
      i.id_null = is_null;
      grew = grew || (cap != i.id_value.capacity ());
    }

    if (grew)
      i.version++;
  }

  const char access::object_traits_impl< ::bpkg::git_repository_state, id_sqlite >::persist_statement[] =
  "INSERT INTO \"git_repository_state\" "
  "(\"url\", "
  "\"directory\", "
  "\"session\", "
  "\"access_time\") "
  "VALUES "
  "(?, ?, ?, ?)";

  const char access::object_traits_impl< ::bpkg::git_repository_state, id_sqlite >::find_statement[] =
  "SELECT "
  "\"git_repository_state\".\"url\", "
  "\"git_repository_state\".\"directory\", "
  "\"git_repository_state\".\"session\", "
  "\"git_repository_state\".\"access_time\" "
  "FROM \"git_repository_state\" "
  "WHERE \"git_repository_state\".\"url\"=?";

  const char access::object_traits_impl< ::bpkg::git_repository_state, id_sqlite >::update_statement[] =
  "UPDATE \"git_repository_state\" "
  "SET "
  "\"directory\"=?, "
  "\"session\"=?, "
  "\"access_time\"=? "
  "WHERE \"url\"=?";

  const char access::object_traits_impl< ::bpkg::git_repository_state, id_sqlite >::erase_statement[] =
  "DELETE FROM \"git_repository_state\" "
  "WHERE \"url\"=?";

  const char access::object_traits_impl< ::bpkg::git_repository_state, id_sqlite >::query_statement[] =
  "SELECT "
  "\"git_repository_state\".\"url\", "
  "\"git_repository_state\".\"directory\", "
  "\"git_repository_state\".\"session\", "
  "\"git_repository_state\".\"access_time\" "
  "FROM \"git_repository_state\"";

  const char access::object_traits_impl< ::bpkg::git_repository_state, id_sqlite >::erase_query_statement[] =
  "DELETE FROM \"git_repository_state\"";

  const char access::object_traits_impl< ::bpkg::git_repository_state, id_sqlite >::table_name[] =
  "\"git_repository_state\"";

  void access::object_traits_impl< ::bpkg::git_repository_state, id_sqlite >::
  persist (database& db, const object_type& obj)
  {
    using namespace sqlite;

    sqlite::connection& conn (
      sqlite::transaction::current ().connection (db));
    statements_type& sts (
      conn.statement_cache ().find_object<object_type> ());

    callback (db,
              obj,
              callback_event::pre_persist);

    image_type& im (sts.image ());
    binding& imb (sts.insert_image_binding ());

    if (init (im, obj, statement_insert))
      im.version++;

    if (im.version != sts.insert_image_version () ||
        imb.version == 0)
    {
      bind (imb.bind, im, statement_insert);
      sts.insert_image_version (im.version);
      imb.version++;
    }

    insert_statement& st (sts.persist_statement ());
    if (!st.execute ())
      throw object_already_persistent ();

    callback (db,
              obj,
              callback_event::post_persist);
  }

  void access::object_traits_impl< ::bpkg::git_repository_state, id_sqlite >::
  update (database& db, const object_type& obj)
  {
    ODB_POTENTIALLY_UNUSED (db);

    using namespace sqlite;
    using sqlite::update_statement;

    callback (db, obj, callback_event::pre_update);

    sqlite::transaction& tr (sqlite::transaction::current ());
    sqlite::connection& conn (tr.connection (db));
    statements_type& sts (
      conn.statement_cache ().find_object<object_type> ());

    id_image_type& idi (sts.id_image ());
    init (idi, id (obj));

    image_type& im (sts.image ());
    if (init (im, obj, statement_update))
      im.version++;

    bool u (false);
    binding& imb (sts.update_image_binding ());
    if (im.version != sts.update_image_version () ||
        imb.version == 0)
    {
      bind (imb.bind, im, statement_update);
      sts.update_image_version (im.version);
      imb.version++;
      u = true;
    }

    binding& idb (sts.id_image_binding ());
    if (idi.version != sts.update_id_image_version () ||
        idb.version == 0)
    {
      if (idi.version != sts.id_image_version () ||
          idb.version == 0)
      {
        bind (idb.bind, idi);
        sts.id_image_version (idi.version);
        idb.version++;
      }

      sts.update_id_image_version (idi.version);

      if (!u)
        imb.version++;
    }

    update_statement& st (sts.update_statement ());
    if (st.execute () == 0)
      throw object_not_persistent ();

    callback (db, obj, callback_event::post_update);
    pointer_cache_traits::update (db, obj);
  }

  void access::object_traits_impl< ::bpkg::git_repository_state, id_sqlite >::
  erase (database& db, const id_type& id)
  {
    using namespace sqlite;

    sqlite::connection& conn (
      sqlite::transaction::current ().connection (db));
    statements_type& sts (
      conn.statement_cache ().find_object<object_type> ());

    id_image_type& i (sts.id_image ());
    init (i, id);

    binding& idb (sts.id_image_binding ());
    if (i.version != sts.id_image_version () || idb.version == 0)
    {
      bind (idb.bind, i);
      sts.id_image_version (i.version);
      idb.version++;
    }

    if (sts.erase_statement ().execute () != 1)
      throw object_not_persistent ();

    pointer_cache_traits::erase (db, id);
  }

  access::object_traits_impl< ::bpkg::git_repository_state, id_sqlite >::pointer_type
  access::object_traits_impl< ::bpkg::git_repository_state, id_sqlite >::
  find (database& db, const id_type& id)
  {
    using namespace sqlite;

    {
      pointer_type p (pointer_cache_traits::find (db, id));

      if (!pointer_traits::null_ptr (p))
        return p;
    }

    sqlite::connection& conn (
      sqlite::transaction::current ().connection (db));
    statements_type& sts (
      conn.statement_cache ().find_object<object_type> ());

    statements_type::auto_lock l (sts);

    if (l.locked ())
    {
      if (!find_ (sts, &id))
        return pointer_type ();
    }

    pointer_type p (
      access::object_factory<object_type, pointer_type>::create ());
    pointer_traits::guard pg (p);

    pointer_cache_traits::insert_guard ig (
      pointer_cache_traits::insert (db, id, p));

    object_type& obj (pointer_traits::get_ref (p));

    if (l.locked ())
    {
      select_statement& st (sts.find_statement ());
      ODB_POTENTIALLY_UNUSED (st);

      callback (db, obj, callback_event::pre_load);
      init (obj, sts.image (), &db);
      load_ (sts, obj, false);
      sts.load_delayed (0);
      l.unlock ();
      callback (db, obj, callback_event::post_load);
      pointer_cache_traits::load (ig.position ());
    }
    else
      sts.delay_load (id, obj, ig.position ());

    ig.release ();
    pg.release ();
    return p;
  }

  bool access::object_traits_impl< ::bpkg::git_repository_state, id_sqlite >::
  find (database& db, const id_type& id, object_type& obj)
  {
    using namespace sqlite;

    sqlite::connection& conn (
      sqlite::transaction::current ().connection (db));
    statements_type& sts (
      conn.statement_cache ().find_object<object_type> ());

    statements_type::auto_lock l (sts);
    assert (l.locked ()) /* Must be a top-level call. */;

    if (!find_ (sts, &id))
      return false;

    select_statement& st (sts.find_statement ());
    ODB_POTENTIALLY_UNUSED (st);

    reference_cache_traits::position_type pos (
      reference_cache_traits::insert (db, id, obj));
    reference_cache_traits::insert_guard ig (pos);

    callback (db, obj, callback_event::pre_load);
    init (obj, sts.image (), &db);
    load_ (sts, obj, false);
    sts.load_delayed (0);
    l.unlock ();
    callback (db, obj, callback_event::post_load);
    reference_cache_traits::load (pos);
    ig.release ();
    return true;
  }

  bool access::object_traits_impl< ::bpkg::git_repository_state, id_sqlite >::
  reload (database& db, object_type& obj)
  {
    using namespace sqlite;

    sqlite::connection& conn (
      sqlite::transaction::current ().connection (db));
    statements_type& sts (
      conn.statement_cache ().find_object<object_type> ());

    statements_type::auto_lock l (sts);
    assert (l.locked ()) /* Must be a top-level call. */;

    const id_type& id (object_traits_impl::id (obj));
    if (!find_ (sts, &id))
      return false;

    select_statement& st (sts.find_statement ());
    ODB_POTENTIALLY_UNUSED (st);

    callback (db, obj, callback_event::pre_load);
    init (obj, sts.image (), &db);
    load_ (sts, obj, true);
    sts.load_delayed (0);
    l.unlock ();
    callback (db, obj, callback_event::post_load);
    return true;
  }

  bool access::object_traits_impl< ::bpkg::git_repository_state, id_sqlite >::
  find_ (statements_type& sts,
         const id_type* id)
  {
    using namespace sqlite;

    id_image_type& i (sts.id_image ());
    init (i, *id);

    binding& idb (sts.id_image_binding ());
    if (i.version != sts.id_image_version () || idb.version == 0)
    {
      bind (idb.bind, i);
      sts.id_image_version (i.version);
      idb.version++;
    }

    image_type& im (sts.image ());
    binding& imb (sts.select_image_binding ());

    if (im.version != sts.select_image_version () ||
        imb.version == 0)
    {
      bind (imb.bind, im, statement_select);
      sts.select_image_version (im.version);
      imb.version++;
    }

    select_statement& st (sts.find_statement ());

    st.execute ();
    auto_result ar (st);
    select_statement::result r (st.fetch ());

    if (r == select_statement::truncated)
    {
      if (grow (im, sts.select_image_truncated ()))
        im.version++;

      if (im.version != sts.select_image_version ())
      {
        bind (imb.bind, im, statement_select);
        sts.select_image_version (im.version);
        imb.version++;
        st.refetch ();
      }
    }

    return r != select_statement::no_data;
  }

  result< access::object_traits_impl< ::bpkg::git_repository_state, id_sqlite >::object_type >
  access::object_traits_impl< ::bpkg::git_repository_state, id_sqlite >::
  query (database& db, const query_base_type& q)
  {
    using namespace sqlite;
    using odb::details::shared;
    using odb::details::shared_ptr;

    sqlite::connection& conn (
      sqlite::transaction::current ().connection (db));

    statements_type& sts (
      conn.statement_cache ().find_object<object_type> ());

    image_type& im (sts.image ());
    binding& imb (sts.select_image_binding ());

    if (im.version != sts.select_image_version () ||
        imb.version == 0)
    {
      bind (imb.bind, im, statement_select);
      sts.select_image_version (im.version);
      imb.version++;
    }

    std::string text (query_statement);
    if (!q.empty ())
    {
      text += " ";
      text += q.clause ();
    }

    q.init_parameters ();
    shared_ptr<select_statement> st (
      new (shared) select_statement (
        conn,
        text,
        false,
        true,
        q.parameters_binding (),
        imb));

    st->execute ();

    shared_ptr< odb::object_result_impl<object_type> > r (
      new (shared) sqlite::object_result_impl<object_type> (
        q, st, sts, 0));

    return result<object_type> (r);
  }

  unsigned long long access::object_traits_impl< ::bpkg::git_repository_state, id_sqlite >::
  erase_query (database& db, const query_base_type& q)
  {
    using namespace sqlite;

    sqlite::connection& conn (
      sqlite::transaction::current ().connection (db));

    std::string text (erase_query_statement);
    if (!q.empty ())
    {
      text += ' ';
      text += q.clause ();
    }

    q.init_parameters ();
    delete_statement st (
      conn,
      text,
      q.parameters_binding ());

    return st.execute ();
  }

  // shared_source_directory
  //

  struct access::object_traits_impl< ::bpkg::shared_source_directory, id_sqlite >::extra_statement_cache_type
  {
    sqlite::container_statements_impl< untracked_configurations_traits > untracked_configurations;

    sqlite::section_statements< ::bpkg::shared_source_directory, untracked_configurations_section_traits > untracked_configurations_section;

    extra_statement_cache_type (
      sqlite::connection& c,
      image_type& im,
      id_image_type& idim,
      sqlite::binding& id,
      sqlite::binding& idv)
    : untracked_configurations (c, id),
      untracked_configurations_section (c, im, idim, id, idv)
    {
    }
  };

  // untracked_configurations
  //

  const char access::object_traits_impl< ::bpkg::shared_source_directory, id_sqlite >::untracked_configurations_traits::
  select_statement[] =
  "SELECT "
  "\"shared_source_directory_untracked_configurations\".\"src_root_file\" "
  "FROM \"shared_source_directory_untracked_configurations\" "
  "WHERE \"shared_source_directory_untracked_configurations\".\"name\"=? AND \"shared_source_directory_untracked_configurations\".\"version_epoch\"=? AND \"shared_source_directory_untracked_configurations\".\"version_canonical_upstream\"=? AND \"shared_source_directory_untracked_configurations\".\"version_canonical_release\"=? AND \"shared_source_directory_untracked_configurations\".\"version_revision\"=? AND \"shared_source_directory_untracked_configurations\".\"version_iteration\"=?";

  const char access::object_traits_impl< ::bpkg::shared_source_directory, id_sqlite >::untracked_configurations_traits::
  insert_statement[] =
  "INSERT INTO \"shared_source_directory_untracked_configurations\" "
  "(\"name\", "
  "\"version_epoch\", "
  "\"version_canonical_upstream\", "
  "\"version_canonical_release\", "
  "\"version_revision\", "
  "\"version_iteration\", "
  "\"src_root_file\") "
  "VALUES "
  "(?, ?, ?, ?, ?, ?, ?)";

  const char access::object_traits_impl< ::bpkg::shared_source_directory, id_sqlite >::untracked_configurations_traits::
  delete_statement[] =
  "DELETE FROM \"shared_source_directory_untracked_configurations\" "
  "WHERE \"name\"=? AND \"version_epoch\"=? AND \"version_canonical_upstream\"=? AND \"version_canonical_release\"=? AND \"version_revision\"=? AND \"version_iteration\"=?";

  void access::object_traits_impl< ::bpkg::shared_source_directory, id_sqlite >::untracked_configurations_traits::
  bind (sqlite::bind* b,
        const sqlite::bind* id,
        std::size_t id_size,
        data_image_type& d)
  {
    using namespace sqlite;

    statement_kind sk (statement_select);
    ODB_POTENTIALLY_UNUSED (sk);

    size_t n (0);

    // object_id
    //
    if (id != 0)
      std::memcpy (&b[n], id, id_size * sizeof (id[0]));
    n += id_size;

    // value
    //
    b[n].type = sqlite::image_traits<
      ::std::string,
      sqlite::id_text>::bind_value;
    b[n].buffer = d.value_value.data ();
    b[n].size = &d.value_size;
    b[n].capacity = d.value_value.capacity ();
    b[n].is_null = &d.value_null;
  }

  void access::object_traits_impl< ::bpkg::shared_source_directory, id_sqlite >::untracked_configurations_traits::
  grow (data_image_type& i,
        bool* t)
  {
    bool grew (false);

    // value
    //
    if (t[0UL])
    {
      i.value_value.capacity (i.value_size);
      grew = true;
    }

    if (grew)
      i.version++;
  }

  void access::object_traits_impl< ::bpkg::shared_source_directory, id_sqlite >::untracked_configurations_traits::
  init (data_image_type& i,
        const value_type& v)
  {
    using namespace sqlite;

    statement_kind sk (statement_insert);
    ODB_POTENTIALLY_UNUSED (sk);

    bool grew (false);

    // value
    //
    {
      // From package-common.hxx:72:14
      ::std::string const& vt =
        (v).representation ();

      bool is_null (false);
      std::size_t cap (i.value_value.capacity ());
      sqlite::value_traits<
          ::std::string,
          sqlite::id_text >::set_image (
        i.value_value,
        i.value_size,
        is_null,
        vt);
      i.value_null = is_null;
      grew = grew || (cap != i.value_value.capacity ());
    }

    if (grew)
      i.version++;
  }

  void access::object_traits_impl< ::bpkg::shared_source_directory, id_sqlite >::untracked_configurations_traits::
  init (value_type& v,
        const data_image_type& i,
        database* db)
  {
    ODB_POTENTIALLY_UNUSED (db);

    // value
    //
    {
      ::std::string vt;

      sqlite::value_traits<
          ::std::string,
          sqlite::id_text >::set_value (
        vt,
        i.value_value,
        i.value_size,
        i.value_null);

      // From package-common.hxx:72:14
      v = bpkg::path (vt);
    }
  }

  void access::object_traits_impl< ::bpkg::shared_source_directory, id_sqlite >::untracked_configurations_traits::
  insert (index_type, const value_type& v, void* d)
  {
    using namespace sqlite;

    statements_type& sts (*static_cast< statements_type* > (d));
    data_image_type& di (sts.data_image ());

    init (di, v);

    if (sts.data_binding_test_version ())
    {
      const binding& id (sts.id_binding ());
      bind (sts.data_bind (), id.bind, id.count, di);
      sts.data_binding_update_version ();
    }

    if (!sts.insert_statement ().execute ())
      throw object_already_persistent ();
  }

  bool access::object_traits_impl< ::bpkg::shared_source_directory, id_sqlite >::untracked_configurations_traits::
  select (index_type&, value_type& v, void* d)
  {
    using namespace sqlite;
    using sqlite::select_statement;

    statements_type& sts (*static_cast< statements_type* > (d));
    data_image_type& di (sts.data_image ());

    init (v, di, &sts.connection ().database ());

    select_statement& st (sts.select_statement ());
    select_statement::result r (st.fetch ());

    if (r == select_statement::truncated)
    {
      grow (di, sts.select_image_truncated ());

      if (sts.data_binding_test_version ())
      {
        bind (sts.data_bind (), 0, sts.id_binding ().count, di);
        sts.data_binding_update_version ();
        st.refetch ();
      }
    }

    return r != select_statement::no_data;
  }

  void access::object_traits_impl< ::bpkg::shared_source_directory, id_sqlite >::untracked_configurations_traits::
  delete_ (void* d)
  {
    using namespace sqlite;

    statements_type& sts (*static_cast< statements_type* > (d));
    sts.delete_statement ().execute ();
  }

  void access::object_traits_impl< ::bpkg::shared_source_directory, id_sqlite >::untracked_configurations_traits::
  persist (const container_type& c,
           statements_type& sts)
  {
    using namespace sqlite;

    functions_type& fs (sts.functions ());
    fs.ordered_ = false;
    container_traits_type::persist (c, fs);
  }

  void access::object_traits_impl< ::bpkg::shared_source_directory, id_sqlite >::untracked_configurations_traits::
  load (container_type& c,
        statements_type& sts)
  {
    using namespace sqlite;
    using sqlite::select_statement;

    const binding& id (sts.id_binding ());

    if (sts.data_binding_test_version ())
    {
      bind (sts.data_bind (), id.bind, id.count, sts.data_image ());
      sts.data_binding_update_version ();
    }

    select_statement& st (sts.select_statement ());
    st.execute ();
    auto_result ar (st);
    select_statement::result r (st.fetch ());

    if (r == select_statement::truncated)
    {
      data_image_type& di (sts.data_image ());
      grow (di, sts.select_image_truncated ());

      if (sts.data_binding_test_version ())
      {
        bind (sts.data_bind (), 0, id.count, di);
        sts.data_binding_update_version ();
        st.refetch ();
      }
    }

    bool more (r != select_statement::no_data);

    functions_type& fs (sts.functions ());
    fs.ordered_ = false;
    container_traits_type::load (c, more, fs);
  }

  void access::object_traits_impl< ::bpkg::shared_source_directory, id_sqlite >::untracked_configurations_traits::
  update (const container_type& c,
          statements_type& sts)
  {
    using namespace sqlite;

    functions_type& fs (sts.functions ());
    fs.ordered_ = false;
    container_traits_type::update (c, fs);
  }

  void access::object_traits_impl< ::bpkg::shared_source_directory, id_sqlite >::untracked_configurations_traits::
  erase (statements_type& sts)
  {
    using namespace sqlite;

    functions_type& fs (sts.functions ());
    fs.ordered_ = false;
    container_traits_type::erase (fs);
  }

  // untracked_configurations_section
  //

  void access::object_traits_impl< ::bpkg::shared_source_directory, id_sqlite >::untracked_configurations_section_traits::
  load (extra_statement_cache_type& esc, object_type& obj)
  {
    // untracked_configurations
    //
    {
      ::bpkg::paths& v =
        obj.untracked_configurations;

      untracked_configurations_traits::load (
        v,
        esc.untracked_configurations);
    }
  }

  void access::object_traits_impl< ::bpkg::shared_source_directory, id_sqlite >::untracked_configurations_section_traits::
  update (extra_statement_cache_type& esc, const object_type& obj)
  {
    // untracked_configurations
    //
    {
      ::bpkg::paths const& v =
        obj.untracked_configurations;

      untracked_configurations_traits::update (
        v,
        esc.untracked_configurations);
    }
  }

  access::object_traits_impl< ::bpkg::shared_source_directory, id_sqlite >::id_type
  access::object_traits_impl< ::bpkg::shared_source_directory, id_sqlite >::
  id (const image_type& i)
  {
    sqlite::database* db (0);
    ODB_POTENTIALLY_UNUSED (db);

    id_type id;
    {
      composite_value_traits< ::bpkg::package_id, id_sqlite >::init (
        id,
        i.id_value,
        db);
    }

    return id;
  }

  bool access::object_traits_impl< ::bpkg::shared_source_directory, id_sqlite >::
  grow (image_type& i,
        bool* t)
  {
    ODB_POTENTIALLY_UNUSED (i);
    ODB_POTENTIALLY_UNUSED (t);

    bool grew (false);

    // id
    //
    if (composite_value_traits< ::bpkg::package_id, id_sqlite >::grow (
          i.id_value, t + 0UL))
      grew = true;

    // version
    //
    if (composite_value_traits< ::bpkg::original_version, id_sqlite >::grow (
          i.version_value, t + 6UL))
      grew = true;

    // access_time
    //
    t[8UL] = false;

    // directory
    //
    if (t[9UL])
    {
      i.directory_value.capacity (i.directory_size);
      grew = true;
    }

    // repository
    //
    if (t[10UL])
    {
      i.repository_value.capacity (i.repository_size);
      grew = true;
    }

    // origin_id
    //
    if (t[11UL])
    {
      i.origin_id_value.capacity (i.origin_id_size);
      grew = true;
    }

    // src_root_file
    //
    if (t[12UL])
    {
      i.src_root_file_value.capacity (i.src_root_file_size);
      grew = true;
    }

    return grew;
  }

  void access::object_traits_impl< ::bpkg::shared_source_directory, id_sqlite >::
  bind (sqlite::bind* b,
        image_type& i,
        sqlite::statement_kind sk)
  {
    ODB_POTENTIALLY_UNUSED (sk);

    using namespace sqlite;

    std::size_t n (0);

    // id
    //
    if (sk != statement_update)
    {
      composite_value_traits< ::bpkg::package_id, id_sqlite >::bind (
        b + n, i.id_value, sk);
      n += 6UL;
    }

    // version
    //
    composite_value_traits< ::bpkg::original_version, id_sqlite >::bind (
      b + n, i.version_value, sk);
    n += 2UL;

    // access_time
    //
    b[n].type = sqlite::bind::integer;
    b[n].buffer = &i.access_time_value;
    b[n].is_null = &i.access_time_null;
    n++;

    // directory
    //
    b[n].type = sqlite::image_traits<
      ::std::string,
      sqlite::id_text>::bind_value;
    b[n].buffer = i.directory_value.data ();
    b[n].size = &i.directory_size;
    b[n].capacity = i.directory_value.capacity ();
    b[n].is_null = &i.directory_null;
    n++;

    // repository
    //
    b[n].type = sqlite::image_traits<
      ::bpkg::repository_url,
      sqlite::id_text>::bind_value;
    b[n].buffer = i.repository_value.data ();
    b[n].size = &i.repository_size;
    b[n].capacity = i.repository_value.capacity ();
    b[n].is_null = &i.repository_null;
    n++;

    // origin_id
    //
    b[n].type = sqlite::image_traits<
      ::std::string,
      sqlite::id_text>::bind_value;
    b[n].buffer = i.origin_id_value.data ();
    b[n].size = &i.origin_id_size;
    b[n].capacity = i.origin_id_value.capacity ();
    b[n].is_null = &i.origin_id_null;
    n++;

    // src_root_file
    //
    b[n].type = sqlite::image_traits<
      ::std::string,
      sqlite::id_text>::bind_value;
    b[n].buffer = i.src_root_file_value.data ();
    b[n].size = &i.src_root_file_size;
    b[n].capacity = i.src_root_file_value.capacity ();
    b[n].is_null = &i.src_root_file_null;
    n++;
  }

  void access::object_traits_impl< ::bpkg::shared_source_directory, id_sqlite >::
  bind (sqlite::bind* b, id_image_type& i)
  {
    std::size_t n (0);
    sqlite::statement_kind sk (sqlite::statement_select);
    composite_value_traits< ::bpkg::package_id, id_sqlite >::bind (
      b + n, i.id_value, sk);
  }

  bool access::object_traits_impl< ::bpkg::shared_source_directory, id_sqlite >::
  init (image_type& i,
        const object_type& o,
        sqlite::statement_kind sk)
  {
    ODB_POTENTIALLY_UNUSED (i);
    ODB_POTENTIALLY_UNUSED (o);
    ODB_POTENTIALLY_UNUSED (sk);

    using namespace sqlite;

    bool grew (false);

    // id
    //
    if (sk == statement_insert)
    {
      ::bpkg::package_id const& v =
        o.id;

      if (composite_value_traits< ::bpkg::package_id, id_sqlite >::init (
            i.id_value,
            v,
            sk))
        grew = true;
    }

    // version
    //
    {
      ::bpkg::original_version const& v =
        o.version;

      if (composite_value_traits< ::bpkg::original_version, id_sqlite >::init (
            i.version_value,
            v,
            sk))
        grew = true;
    }

    // access_time
    //
    {
      ::butl::timestamp const& v =
        o.access_time;

      // From package-common.hxx:102:14
      ::uint64_t const& vt =
        std::chrono::duration_cast < std::chrono::nanoseconds > ((v).time_since_epoch ()).count ();

      bool is_null (false);
      sqlite::value_traits<
          ::uint64_t,
          sqlite::id_integer >::set_image (
        i.access_time_value,
        is_null,
        vt);
      i.access_time_null = is_null;
    }

    // directory
    //
    {
      ::butl::dir_path const& v =
        o.directory;

      // From package-common.hxx:79:14
      ::std::string const& vt =
        (v).string ();

      bool is_null (false);
      std::size_t cap (i.directory_value.capacity ());
      sqlite::value_traits<
          ::std::string,
          sqlite::id_text >::set_image (
        i.directory_value,
        i.directory_size,
        is_null,
        vt);
      i.directory_null = is_null;
      grew = grew || (cap != i.directory_value.capacity ());
    }

    // repository
    //
    {
      ::bpkg::repository_url const& v =
        o.repository;

      bool is_null (false);
      std::size_t cap (i.repository_value.capacity ());
      sqlite::value_traits<
          ::bpkg::repository_url,
          sqlite::id_text >::set_image (
        i.repository_value,
        i.repository_size,
        is_null,
        v);
      i.repository_null = is_null;
      grew = grew || (cap != i.repository_value.capacity ());
    }

    // origin_id
    //
    {
      ::std::string const& v =
        o.origin_id;

      bool is_null (false);
      std::size_t cap (i.origin_id_value.capacity ());
      sqlite::value_traits<
          ::std::string,
          sqlite::id_text >::set_image (
        i.origin_id_value,
        i.origin_id_size,
        is_null,
        v);
      i.origin_id_null = is_null;
      grew = grew || (cap != i.origin_id_value.capacity ());
    }

    // src_root_file
    //
    {
      ::butl::path const& v =
        o.src_root_file;

      // From package-common.hxx:72:14
      ::std::string const& vt =
        (v).representation ();

      bool is_null (false);
      std::size_t cap (i.src_root_file_value.capacity ());
      sqlite::value_traits<
          ::std::string,
          sqlite::id_text >::set_image (
        i.src_root_file_value,
        i.src_root_file_size,
        is_null,
        vt);
      i.src_root_file_null = is_null;
      grew = grew || (cap != i.src_root_file_value.capacity ());
    }

    return grew;
  }

  void access::object_traits_impl< ::bpkg::shared_source_directory, id_sqlite >::
  init (object_type& o,
        const image_type& i,
        database* db)
  {
    ODB_POTENTIALLY_UNUSED (o);
    ODB_POTENTIALLY_UNUSED (i);
    ODB_POTENTIALLY_UNUSED (db);

    // id
    //
    {
      ::bpkg::package_id& v =
        o.id;

      composite_value_traits< ::bpkg::package_id, id_sqlite >::init (
        v,
        i.id_value,
        db);
    }

    // version
    //
    {
      // From fetch-cache-data.hxx:304:32
      ::bpkg::original_version v;

      composite_value_traits< ::bpkg::original_version, id_sqlite >::init (
        v,
        i.version_value,
        db);

      // From fetch-cache-data.hxx:304:32
      o.version.init (o.id.version, (v));
    }

    // access_time
    //
    {
      ::butl::timestamp& v =
        o.access_time;

      ::uint64_t vt;

      sqlite::value_traits<
          ::uint64_t,
          sqlite::id_integer >::set_value (
        vt,
        i.access_time_value,
        i.access_time_null);

      // From package-common.hxx:102:14
      v = butl::timestamp (std::chrono::duration_cast < butl::timestamp::duration > (std::chrono::nanoseconds (vt)));
    }

    // directory
    //
    {
      ::butl::dir_path& v =
        o.directory;

      ::std::string vt;

      sqlite::value_traits<
          ::std::string,
          sqlite::id_text >::set_value (
        vt,
        i.directory_value,
        i.directory_size,
        i.directory_null);

      // From package-common.hxx:79:14
      v = bpkg::dir_path (vt);
    }

    // repository
    //
    {
      ::bpkg::repository_url& v =
        o.repository;

      sqlite::value_traits<
          ::bpkg::repository_url,
          sqlite::id_text >::set_value (
        v,
        i.repository_value,
        i.repository_size,
        i.repository_null);
    }

    // origin_id
    //
    {
      ::std::string& v =
        o.origin_id;

      sqlite::value_traits<
          ::std::string,
          sqlite::id_text >::set_value (
        v,
        i.origin_id_value,
        i.origin_id_size,
        i.origin_id_null);
    }

    // src_root_file
    //
    {
      ::butl::path& v =
        o.src_root_file;

      ::std::string vt;

      sqlite::value_traits<
          ::std::string,
          sqlite::id_text >::set_value (
        vt,
        i.src_root_file_value,
        i.src_root_file_size,
        i.src_root_file_null);

      // From package-common.hxx:72:14
      v = bpkg::path (vt);
    }
  }

  void access::object_traits_impl< ::bpkg::shared_source_directory, id_sqlite >::
  init (id_image_type& i, const id_type& id)
  {
    bool grew (false);
    sqlite::statement_kind sk (sqlite::statement_select);
    {
      if (composite_value_traits< ::bpkg::package_id, id_sqlite >::init (
            i.id_value,
            id,
            sk))
        grew = true;
    }

    if (grew)
      i.version++;
  }

  const char access::object_traits_impl< ::bpkg::shared_source_directory, id_sqlite >::persist_statement[] =
  "INSERT INTO \"shared_source_directory\" "
  "(\"name\", "
  "\"version_epoch\", "
  "\"version_canonical_upstream\", "
  "\"version_canonical_release\", "
  "\"version_revision\", "
  "\"version_iteration\", "
  "\"version_upstream\", "
  "\"version_release\", "
  "\"access_time\", "
  "\"directory\", "
  "\"repository\", "
  "\"origin_id\", "
  "\"src_root_file\") "
  "VALUES "
  "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";

  const char access::object_traits_impl< ::bpkg::shared_source_directory, id_sqlite >::find_statement[] =
  "SELECT "
  "\"shared_source_directory\".\"name\", "
  "\"shared_source_directory\".\"version_epoch\", "
  "\"shared_source_directory\".\"version_canonical_upstream\", "
  "\"shared_source_directory\".\"version_canonical_release\", "
  "\"shared_source_directory\".\"version_revision\", "
  "\"shared_source_directory\".\"version_iteration\", "
  "\"shared_source_directory\".\"version_upstream\", "
  "\"shared_source_directory\".\"version_release\", "
  "\"shared_source_directory\".\"access_time\", "
  "\"shared_source_directory\".\"directory\", "
  "\"shared_source_directory\".\"repository\", "
  "\"shared_source_directory\".\"origin_id\", "
  "\"shared_source_directory\".\"src_root_file\" "
  "FROM \"shared_source_directory\" "
  "WHERE \"shared_source_directory\".\"name\"=? AND \"shared_source_directory\".\"version_epoch\"=? AND \"shared_source_directory\".\"version_canonical_upstream\"=? AND \"shared_source_directory\".\"version_canonical_release\"=? AND \"shared_source_directory\".\"version_revision\"=? AND \"shared_source_directory\".\"version_iteration\"=?";

  const char access::object_traits_impl< ::bpkg::shared_source_directory, id_sqlite >::update_statement[] =
  "UPDATE \"shared_source_directory\" "
  "SET "
  "\"version_upstream\"=?, "
  "\"version_release\"=?, "
  "\"access_time\"=?, "
  "\"directory\"=?, "
  "\"repository\"=?, "
  "\"origin_id\"=?, "
  "\"src_root_file\"=? "
  "WHERE \"name\"=? AND \"version_epoch\"=? AND \"version_canonical_upstream\"=? AND \"version_canonical_release\"=? AND \"version_revision\"=? AND \"version_iteration\"=?";

  const char access::object_traits_impl< ::bpkg::shared_source_directory, id_sqlite >::erase_statement[] =
  "DELETE FROM \"shared_source_directory\" "
  "WHERE \"name\"=? AND \"version_epoch\"=? AND \"version_canonical_upstream\"=? AND \"version_canonical_release\"=? AND \"version_revision\"=? AND \"version_iteration\"=?";

  const char access::object_traits_impl< ::bpkg::shared_source_directory, id_sqlite >::query_statement[] =
  "SELECT "
  "\"shared_source_directory\".\"name\", "
  "\"shared_source_directory\".\"version_epoch\", "
  "\"shared_source_directory\".\"version_canonical_upstream\", "
  "\"shared_source_directory\".\"version_canonical_release\", "
  "\"shared_source_directory\".\"version_revision\", "
  "\"shared_source_directory\".\"version_iteration\", "
  "\"shared_source_directory\".\"version_upstream\", "
  "\"shared_source_directory\".\"version_release\", "
  "\"shared_source_directory\".\"access_time\", "
  "\"shared_source_directory\".\"directory\", "
  "\"shared_source_directory\".\"repository\", "
  "\"shared_source_directory\".\"origin_id\", "
  "\"shared_source_directory\".\"src_root_file\" "
  "FROM \"shared_source_directory\"";

  const char access::object_traits_impl< ::bpkg::shared_source_directory, id_sqlite >::erase_query_statement[] =
  "DELETE FROM \"shared_source_directory\"";

  const char access::object_traits_impl< ::bpkg::shared_source_directory, id_sqlite >::table_name[] =
  "\"shared_source_directory\"";

  void access::object_traits_impl< ::bpkg::shared_source_directory, id_sqlite >::
  persist (database& db, const object_type& obj)
  {
    using namespace sqlite;

    sqlite::connection& conn (
      sqlite::transaction::current ().connection (db));
    statements_type& sts (
      conn.statement_cache ().find_object<object_type> ());

    callback (db,
              obj,
              callback_event::pre_persist);

    image_type& im (sts.image ());
    binding& imb (sts.insert_image_binding ());

    if (init (im, obj, statement_insert))
      im.version++;

    if (im.version != sts.insert_image_version () ||
        imb.version == 0)
    {
      bind (imb.bind, im, statement_insert);
      sts.insert_image_version (im.version);
      imb.version++;
    }

    insert_statement& st (sts.persist_statement ());
    if (!st.execute ())
      throw object_already_persistent ();

    id_image_type& i (sts.id_image ());
    init (i, id (obj));

    binding& idb (sts.id_image_binding ());
    if (i.version != sts.id_image_version () || idb.version == 0)
    {
      bind (idb.bind, i);
      sts.id_image_version (i.version);
      idb.version++;
    }

    extra_statement_cache_type& esc (sts.extra_statement_cache ());

    // untracked_configurations
    //
    {
      ::bpkg::paths const& v =
        obj.untracked_configurations;

      untracked_configurations_traits::persist (
        v,
        esc.untracked_configurations);
    }

    obj.untracked_configurations_section.reset (true, false);

    callback (db,
              obj,
              callback_event::post_persist);
  }

  void access::object_traits_impl< ::bpkg::shared_source_directory, id_sqlite >::
  update (database& db, const object_type& obj)
  {
    ODB_POTENTIALLY_UNUSED (db);

    using namespace sqlite;
    using sqlite::update_statement;

    callback (db, obj, callback_event::pre_update);

    sqlite::transaction& tr (sqlite::transaction::current ());
    sqlite::connection& conn (tr.connection (db));
    statements_type& sts (
      conn.statement_cache ().find_object<object_type> ());

    id_image_type& idi (sts.id_image ());
    init (idi, id (obj));

    image_type& im (sts.image ());
    if (init (im, obj, statement_update))
      im.version++;

    bool u (false);
    binding& imb (sts.update_image_binding ());
    if (im.version != sts.update_image_version () ||
        imb.version == 0)
    {
      bind (imb.bind, im, statement_update);
      sts.update_image_version (im.version);
      imb.version++;
      u = true;
    }

    binding& idb (sts.id_image_binding ());
    if (idi.version != sts.update_id_image_version () ||
        idb.version == 0)
    {
      if (idi.version != sts.id_image_version () ||
          idb.version == 0)
      {
        bind (idb.bind, idi);
        sts.id_image_version (idi.version);
        idb.version++;
      }

      sts.update_id_image_version (idi.version);

      if (!u)
        imb.version++;
    }

    update_statement& st (sts.update_statement ());
    if (st.execute () == 0)
      throw object_not_persistent ();

    extra_statement_cache_type& esc (sts.extra_statement_cache ());

    if (obj.untracked_configurations_section.loaded ())
    {
      untracked_configurations_section_traits::update (esc, obj);
    }

    callback (db, obj, callback_event::post_update);
    pointer_cache_traits::update (db, obj);
  }

  void access::object_traits_impl< ::bpkg::shared_source_directory, id_sqlite >::
  erase (database& db, const id_type& id)
  {
    using namespace sqlite;

    sqlite::connection& conn (
      sqlite::transaction::current ().connection (db));
    statements_type& sts (
      conn.statement_cache ().find_object<object_type> ());

    id_image_type& i (sts.id_image ());
    init (i, id);

    binding& idb (sts.id_image_binding ());
    if (i.version != sts.id_image_version () || idb.version == 0)
    {
      bind (idb.bind, i);
      sts.id_image_version (i.version);
      idb.version++;
    }

    extra_statement_cache_type& esc (sts.extra_statement_cache ());

    // untracked_configurations
    //
    {
      untracked_configurations_traits::erase (
        esc.untracked_configurations);
    }

    if (sts.erase_statement ().execute () != 1)
      throw object_not_persistent ();

    pointer_cache_traits::erase (db, id);
  }

  access::object_traits_impl< ::bpkg::shared_source_directory, id_sqlite >::pointer_type
  access::object_traits_impl< ::bpkg::shared_source_directory, id_sqlite >::
  find (database& db, const id_type& id)
  {
    using namespace sqlite;

    {
      pointer_type p (pointer_cache_traits::find (db, id));

      if (!pointer_traits::null_ptr (p))
        return p;
    }

    sqlite::connection& conn (
      sqlite::transaction::current ().connection (db));
    statements_type& sts (
      conn.statement_cache ().find_object<object_type> ());

    statements_type::auto_lock l (sts);

    if (l.locked ())
    {
      if (!find_ (sts, &id))
        return pointer_type ();
    }

    pointer_type p (
      access::object_factory<object_type, pointer_type>::create ());
    pointer_traits::guard pg (p);

    pointer_cache_traits::insert_guard ig (
      pointer_cache_traits::insert (db, id, p));

    object_type& obj (pointer_traits::get_ref (p));

    if (l.locked ())
    {
      select_statement& st (sts.find_statement ());
      ODB_POTENTIALLY_UNUSED (st);

      callback (db, obj, callback_event::pre_load);
      init (obj, sts.image (), &db);
      load_ (sts, obj, false);
      sts.load_delayed (0);
      l.unlock ();
      callback (db, obj, callback_event::post_load);
      pointer_cache_traits::load (ig.position ());
    }
    else
      sts.delay_load (id, obj, ig.position ());

    ig.release ();
    pg.release ();
    return p;
  }

  bool access::object_traits_impl< ::bpkg::shared_source_directory, id_sqlite >::
  find (database& db, const id_type& id, object_type& obj)
  {
    using namespace sqlite;

    sqlite::connection& conn (
      sqlite::transaction::current ().connection (db));
    statements_type& sts (
      conn.statement_cache ().find_object<object_type> ());

    statements_type::auto_lock l (sts);
    assert (l.locked ()) /* Must be a top-level call. */;

    if (!find_ (sts, &id))
      return false;

    select_statement& st (sts.find_statement ());
    ODB_POTENTIALLY_UNUSED (st);

    reference_cache_traits::position_type pos (
      reference_cache_traits::insert (db, id, obj));
    reference_cache_traits::insert_guard ig (pos);

    callback (db, obj, callback_event::pre_load);
    init (obj, sts.image (), &db);
    load_ (sts, obj, false);
    sts.load_delayed (0);
    l.unlock ();
    callback (db, obj, callback_event::post_load);
    reference_cache_traits::load (pos);
    ig.release ();
    return true;
  }

  bool access::object_traits_impl< ::bpkg::shared_source_directory, id_sqlite >::
  reload (database& db, object_type& obj)
  {
    using namespace sqlite;

    sqlite::connection& conn (
      sqlite::transaction::current ().connection (db));
    statements_type& sts (
      conn.statement_cache ().find_object<object_type> ());

    statements_type::auto_lock l (sts);
    assert (l.locked ()) /* Must be a top-level call. */;

    const id_type& id (object_traits_impl::id (obj));
    if (!find_ (sts, &id))
      return false;

    select_statement& st (sts.find_statement ());
    ODB_POTENTIALLY_UNUSED (st);

    callback (db, obj, callback_event::pre_load);
    init (obj, sts.image (), &db);
    load_ (sts, obj, true);
    sts.load_delayed (0);
    l.unlock ();
    callback (db, obj, callback_event::post_load);
    return true;
  }

  bool access::object_traits_impl< ::bpkg::shared_source_directory, id_sqlite >::
  load (connection& conn, object_type& obj, section& s)
  {
    using namespace sqlite;

    sqlite::connection& c (static_cast<sqlite::connection&> (conn));
    statements_type& sts (c.statement_cache ().find_object<object_type> ());

    statements_type::auto_lock l (sts);
    assert (l.locked ()) /* Must be a top-level call. */;

    bool r (false);

    id_image_type& i (sts.id_image ());
    init (i, id (obj));

    binding& idb (sts.id_image_binding ());
    if (i.version != sts.id_image_version () || idb.version == 0)
    {
      bind (idb.bind, i);
      sts.id_image_version (i.version);
      idb.version++;
    }

    extra_statement_cache_type& esc (sts.extra_statement_cache ());

    if (!r && &s == &obj.untracked_configurations_section)
    {
      untracked_configurations_section_traits::load (esc, obj);
      r = true;
    }

    sts.load_delayed (0);
    l.unlock ();
    return r;
  }

  bool access::object_traits_impl< ::bpkg::shared_source_directory, id_sqlite >::
  update (connection& conn, const object_type& obj, const section& s)
  {
    using namespace sqlite;

    sqlite::connection& c (static_cast<sqlite::connection&> (conn));
    statements_type& sts (c.statement_cache ().find_object<object_type> ());
    extra_statement_cache_type& esc (sts.extra_statement_cache ());

    id_image_type& i (sts.id_image ());
    init (i, id (obj));

    binding& idb (sts.id_image_binding ());
    if (i.version != sts.id_image_version () || idb.version == 0)
    {
      bind (idb.bind, i);
      sts.id_image_version (i.version);
      idb.version++;
    }

    if (&s == &obj.untracked_configurations_section)untracked_configurations_section_traits::update (esc, obj);
    else
      return false;

    return true;
  }

  bool access::object_traits_impl< ::bpkg::shared_source_directory, id_sqlite >::
  find_ (statements_type& sts,
         const id_type* id)
  {
    using namespace sqlite;

    id_image_type& i (sts.id_image ());
    init (i, *id);

    binding& idb (sts.id_image_binding ());
    if (i.version != sts.id_image_version () || idb.version == 0)
    {
      bind (idb.bind, i);
      sts.id_image_version (i.version);
      idb.version++;
    }

    image_type& im (sts.image ());
    binding& imb (sts.select_image_binding ());

    if (im.version != sts.select_image_version () ||
        imb.version == 0)
    {
      bind (imb.bind, im, statement_select);
      sts.select_image_version (im.version);
      imb.version++;
    }

    select_statement& st (sts.find_statement ());

    st.execute ();
    auto_result ar (st);
    select_statement::result r (st.fetch ());

    if (r == select_statement::truncated)
    {
      if (grow (im, sts.select_image_truncated ()))
        im.version++;

      if (im.version != sts.select_image_version ())
      {
        bind (imb.bind, im, statement_select);
        sts.select_image_version (im.version);
        imb.version++;
        st.refetch ();
      }
    }

    return r != select_statement::no_data;
  }

  void access::object_traits_impl< ::bpkg::shared_source_directory, id_sqlite >::
  load_ (statements_type& sts,
         object_type& obj,
         bool reload)
  {
    ODB_POTENTIALLY_UNUSED (reload);

    extra_statement_cache_type& esc (sts.extra_statement_cache ());

    if (reload)
    {
      if (obj.untracked_configurations_section.loaded ())
      {
        untracked_configurations_section_traits::load (esc, obj);
        obj.untracked_configurations_section.reset (true, false);
      }
    }
    else
      obj.untracked_configurations_section.reset ();
  }

  result< access::object_traits_impl< ::bpkg::shared_source_directory, id_sqlite >::object_type >
  access::object_traits_impl< ::bpkg::shared_source_directory, id_sqlite >::
  query (database& db, const query_base_type& q)
  {
    using namespace sqlite;
    using odb::details::shared;
    using odb::details::shared_ptr;

    sqlite::connection& conn (
      sqlite::transaction::current ().connection (db));

    statements_type& sts (
      conn.statement_cache ().find_object<object_type> ());

    image_type& im (sts.image ());
    binding& imb (sts.select_image_binding ());

    if (im.version != sts.select_image_version () ||
        imb.version == 0)
    {
      bind (imb.bind, im, statement_select);
      sts.select_image_version (im.version);
      imb.version++;
    }

    std::string text (query_statement);
    if (!q.empty ())
    {
      text += " ";
      text += q.clause ();
    }

    q.init_parameters ();
    shared_ptr<select_statement> st (
      new (shared) select_statement (
        conn,
        text,
        false,
        true,
        q.parameters_binding (),
        imb));

    st->execute ();

    shared_ptr< odb::object_result_impl<object_type> > r (
      new (shared) sqlite::object_result_impl<object_type> (
        q, st, sts, 0));

    return result<object_type> (r);
  }

  unsigned long long access::object_traits_impl< ::bpkg::shared_source_directory, id_sqlite >::
  erase_query (database& db, const query_base_type& q)
  {
    using namespace sqlite;

    sqlite::connection& conn (
      sqlite::transaction::current ().connection (db));

    std::string text (erase_query_statement);
    if (!q.empty ())
    {
      text += ' ';
      text += q.clause ();
    }

    q.init_parameters ();
    delete_statement st (
      conn,
      text,
      q.parameters_binding ());

    return st.execute ();
  }
}

namespace odb
{
  static bool
  create_schema (database& db, unsigned short pass, bool drop)
  {
    ODB_POTENTIALLY_UNUSED (db);
    ODB_POTENTIALLY_UNUSED (pass);
    ODB_POTENTIALLY_UNUSED (drop);

    if (drop)
    {
      switch (pass)
      {
        case 1:
        {
          return true;
        }
        case 2:
        {
          db.execute ("DROP TABLE IF EXISTS \"shared_source_directory_untracked_configurations\"");
          db.execute ("DROP TABLE IF EXISTS \"shared_source_directory\"");
          db.execute ("DROP TABLE IF EXISTS \"git_repository_state\"");
          db.execute ("DROP TABLE IF EXISTS \"pkg_repository_package\"");
          db.execute ("DROP TABLE IF EXISTS \"pkg_repository_metadata\"");
          db.execute ("DROP TABLE IF EXISTS \"pkg_repository_auth\"");
          db.execute ("CREATE TABLE IF NOT EXISTS \"schema_version\" (\n"
                      "  \"name\" TEXT NOT NULL PRIMARY KEY,\n"
                      "  \"version\" INTEGER NOT NULL,\n"
                      "  \"migration\" INTEGER NOT NULL)");
          db.execute ("DELETE FROM \"schema_version\"\n"
                      "  WHERE \"name\" = 'fetch-cache'");
          return false;
        }
      }
    }
    else
    {
      switch (pass)
      {
        case 1:
        {
          db.execute ("CREATE TABLE \"pkg_repository_auth\" (\n"
                      "  \"id\" TEXT NULL PRIMARY KEY,\n"
                      "  \"fingerprint\" TEXT NULL,\n"
                      "  \"name\" TEXT NULL,\n"
                      "  \"end_date\" INTEGER NULL)");
          db.execute ("CREATE TABLE \"pkg_repository_metadata\" (\n"
                      "  \"url\" TEXT NULL PRIMARY KEY,\n"
                      "  \"directory\" TEXT NULL,\n"
                      "  \"session\" TEXT NULL,\n"
                      "  \"access_time\" INTEGER NULL,\n"
                      "  \"repositories_path\" TEXT NULL,\n"
                      "  \"repositories_checksum\" TEXT NULL,\n"
                      "  \"packages_path\" TEXT NULL,\n"
                      "  \"packages_checksum\" TEXT NULL)");
          db.execute ("CREATE UNIQUE INDEX \"pkg_repository_metadata_directory_i\"\n"
                      "  ON \"pkg_repository_metadata\" (\"directory\")");
          db.execute ("CREATE INDEX \"pkg_repository_metadata_access_time_i\"\n"
                      "  ON \"pkg_repository_metadata\" (\"access_time\")");
          db.execute ("CREATE TABLE \"pkg_repository_package\" (\n"
                      "  \"name\" TEXT NULL COLLATE NOCASE,\n"
                      "  \"version_epoch\" INTEGER NULL,\n"
                      "  \"version_canonical_upstream\" TEXT NULL,\n"
                      "  \"version_canonical_release\" TEXT NULL COLLATE BINARY,\n"
                      "  \"version_revision\" INTEGER NULL,\n"
                      "  \"version_iteration\" INTEGER NULL,\n"
                      "  \"version_upstream\" TEXT NULL,\n"
                      "  \"version_release\" TEXT NULL,\n"
                      "  \"access_time\" INTEGER NULL,\n"
                      "  \"archive\" TEXT NULL,\n"
                      "  \"checksum\" TEXT NULL,\n"
                      "  \"repository\" TEXT NULL,\n"
                      "  PRIMARY KEY (\"name\",\n"
                      "               \"version_epoch\",\n"
                      "               \"version_canonical_upstream\",\n"
                      "               \"version_canonical_release\",\n"
                      "               \"version_revision\",\n"
                      "               \"version_iteration\"))");
          db.execute ("CREATE UNIQUE INDEX \"pkg_repository_package_archive_i\"\n"
                      "  ON \"pkg_repository_package\" (\"archive\")");
          db.execute ("CREATE INDEX \"pkg_repository_package_access_time_i\"\n"
                      "  ON \"pkg_repository_package\" (\"access_time\")");
          db.execute ("CREATE TABLE \"git_repository_state\" (\n"
                      "  \"url\" TEXT NULL PRIMARY KEY,\n"
                      "  \"directory\" TEXT NULL,\n"
                      "  \"session\" TEXT NULL,\n"
                      "  \"access_time\" INTEGER NULL)");
          db.execute ("CREATE UNIQUE INDEX \"git_repository_state_directory_i\"\n"
                      "  ON \"git_repository_state\" (\"directory\")");
          db.execute ("CREATE INDEX \"git_repository_state_access_time_i\"\n"
                      "  ON \"git_repository_state\" (\"access_time\")");
          db.execute ("CREATE TABLE \"shared_source_directory\" (\n"
                      "  \"name\" TEXT NULL COLLATE NOCASE,\n"
                      "  \"version_epoch\" INTEGER NULL,\n"
                      "  \"version_canonical_upstream\" TEXT NULL,\n"
                      "  \"version_canonical_release\" TEXT NULL COLLATE BINARY,\n"
                      "  \"version_revision\" INTEGER NULL,\n"
                      "  \"version_iteration\" INTEGER NULL,\n"
                      "  \"version_upstream\" TEXT NULL,\n"
                      "  \"version_release\" TEXT NULL,\n"
                      "  \"access_time\" INTEGER NULL,\n"
                      "  \"directory\" TEXT NULL,\n"
                      "  \"repository\" TEXT NULL,\n"
                      "  \"origin_id\" TEXT NULL,\n"
                      "  \"src_root_file\" TEXT NULL,\n"
                      "  PRIMARY KEY (\"name\",\n"
                      "               \"version_epoch\",\n"
                      "               \"version_canonical_upstream\",\n"
                      "               \"version_canonical_release\",\n"
                      "               \"version_revision\",\n"
                      "               \"version_iteration\"))");
          db.execute ("CREATE UNIQUE INDEX \"shared_source_directory_directory_i\"\n"
                      "  ON \"shared_source_directory\" (\"directory\")");
          db.execute ("CREATE INDEX \"shared_source_directory_access_time_i\"\n"
                      "  ON \"shared_source_directory\" (\"access_time\")");
          db.execute ("CREATE TABLE \"shared_source_directory_untracked_configurations\" (\n"
                      "  \"name\" TEXT NULL COLLATE NOCASE,\n"
                      "  \"version_epoch\" INTEGER NULL,\n"
                      "  \"version_canonical_upstream\" TEXT NULL,\n"
                      "  \"version_canonical_release\" TEXT NULL COLLATE BINARY,\n"
                      "  \"version_revision\" INTEGER NULL,\n"
                      "  \"version_iteration\" INTEGER NULL,\n"
                      "  \"src_root_file\" TEXT NULL,\n"
                      "  CONSTRAINT \"object_id_fk\"\n"
                      "    FOREIGN KEY (\"name\",\n"
                      "                 \"version_epoch\",\n"
                      "                 \"version_canonical_upstream\",\n"
                      "                 \"version_canonical_release\",\n"
                      "                 \"version_revision\",\n"
                      "                 \"version_iteration\")\n"
                      "    REFERENCES \"shared_source_directory\" (\"name\",\n"
                      "                                          \"version_epoch\",\n"
                      "                                          \"version_canonical_upstream\",\n"
                      "                                          \"version_canonical_release\",\n"
                      "                                          \"version_revision\",\n"
                      "                                          \"version_iteration\")\n"
                      "    ON DELETE CASCADE)");
          db.execute ("CREATE INDEX \"shared_source_directory_untracked_configurations_object_id_i\"\n"
                      "  ON \"shared_source_directory_untracked_configurations\" (\n"
                      "    \"name\",\n"
                      "    \"version_epoch\",\n"
                      "    \"version_canonical_upstream\",\n"
                      "    \"version_canonical_release\",\n"
                      "    \"version_revision\",\n"
                      "    \"version_iteration\")");
          return true;
        }
        case 2:
        {
          db.execute ("CREATE TABLE IF NOT EXISTS \"schema_version\" (\n"
                      "  \"name\" TEXT NOT NULL PRIMARY KEY,\n"
                      "  \"version\" INTEGER NOT NULL,\n"
                      "  \"migration\" INTEGER NOT NULL)");
          db.execute ("INSERT OR IGNORE INTO \"schema_version\" (\n"
                      "  \"name\", \"version\", \"migration\")\n"
                      "  VALUES ('fetch-cache', 1, 0)");
          return false;
        }
      }
    }

    return false;
  }

  static const schema_catalog_create_entry
  create_schema_entry_ (
    id_sqlite,
    "fetch-cache",
    &create_schema);

  static const schema_catalog_migrate_entry
  migrate_schema_entry_1_ (
    id_sqlite,
    "fetch-cache",
    1ULL,
    0);
}

#include <odb/post.hxx>
