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

#include <odb/pre.hxx>

#include <bdep/project-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/container-statements.hxx>
#include <odb/sqlite/exceptions.hxx>
#include <odb/sqlite/simple-object-result.hxx>
#include <odb/sqlite/view-result.hxx>

namespace odb
{
  // package_state
  //

  bool access::composite_value_traits< ::bdep::package_state, id_sqlite >::
  grow (image_type& i,
        bool* t)
  {
    ODB_POTENTIALLY_UNUSED (i);
    ODB_POTENTIALLY_UNUSED (t);

    bool grew (false);

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

    return grew;
  }

  void access::composite_value_traits< ::bdep::package_state, id_sqlite >::
  bind (sqlite::bind* b,
        image_type& i,
        sqlite::statement_kind sk)
  {
    ODB_POTENTIALLY_UNUSED (b);
    ODB_POTENTIALLY_UNUSED (i);
    ODB_POTENTIALLY_UNUSED (sk);

    using namespace sqlite;

    std::size_t n (0);
    ODB_POTENTIALLY_UNUSED (n);

    // name
    //
    b[n].type = sqlite::image_traits<
      ::bpkg::package_name,
      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++;
  }

  bool access::composite_value_traits< ::bdep::package_state, id_sqlite >::
  init (image_type& i,
        const value_type& o,
        sqlite::statement_kind sk)
  {
    ODB_POTENTIALLY_UNUSED (i);
    ODB_POTENTIALLY_UNUSED (o);
    ODB_POTENTIALLY_UNUSED (sk);

    using namespace sqlite;

    bool grew (false);

    // name
    //
    {
      ::bpkg::package_name const& v =
        o.name;

      bool is_null (false);
      std::size_t cap (i.name_value.capacity ());
      sqlite::value_traits<
          ::bpkg::package_name,
          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 ());
    }

    return grew;
  }

  void access::composite_value_traits< ::bdep::package_state, id_sqlite >::
  init (value_type& o,
        const image_type&  i,
        database* db)
  {
    ODB_POTENTIALLY_UNUSED (o);
    ODB_POTENTIALLY_UNUSED (i);
    ODB_POTENTIALLY_UNUSED (db);

    // name
    //
    {
      ::bpkg::package_name& v =
        o.name;

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

  // configuration
  //

  struct access::object_traits_impl< ::bdep::configuration, id_sqlite >::extra_statement_cache_type
  {
    sqlite::container_statements_impl< packages_traits > packages;

    extra_statement_cache_type (
      sqlite::connection& c,
      image_type&,
      id_image_type&,
      sqlite::binding& id,
      sqlite::binding&)
    : packages (c, id)
    {
    }
  };

  // packages
  //

  const char access::object_traits_impl< ::bdep::configuration, id_sqlite >::packages_traits::
  select_statement[] =
  "SELECT "
  "\"configuration_packages\".\"index\", "
  "\"configuration_packages\".\"name\" "
  "FROM \"configuration_packages\" "
  "WHERE \"configuration_packages\".\"object_id\"=? ORDER BY \"configuration_packages\".\"index\"";

  const char access::object_traits_impl< ::bdep::configuration, id_sqlite >::packages_traits::
  insert_statement[] =
  "INSERT INTO \"configuration_packages\" "
  "(\"object_id\", "
  "\"index\", "
  "\"name\") "
  "VALUES "
  "(?, ?, ?)";

  const char access::object_traits_impl< ::bdep::configuration, id_sqlite >::packages_traits::
  delete_statement[] =
  "DELETE FROM \"configuration_packages\" "
  "WHERE \"object_id\"=?";

  void access::object_traits_impl< ::bdep::configuration, id_sqlite >::packages_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;

    // index
    //
    b[n].type = sqlite::bind::integer;
    b[n].buffer = &d.index_value;
    b[n].is_null = &d.index_null;
    n++;

    // value
    //
    composite_value_traits< value_type, id_sqlite >::bind (
      b + n, d.value_value, sk);
  }

  void access::object_traits_impl< ::bdep::configuration, id_sqlite >::packages_traits::
  grow (data_image_type& i,
        bool* t)
  {
    bool grew (false);

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

    // value
    //
    if (composite_value_traits< value_type, id_sqlite >::grow (
          i.value_value, t + 1UL))
      grew = true;

    if (grew)
      i.version++;
  }

  void access::object_traits_impl< ::bdep::configuration, id_sqlite >::packages_traits::
  init (data_image_type& i,
        index_type* j,
        const value_type& v)
  {
    using namespace sqlite;

    statement_kind sk (statement_insert);
    ODB_POTENTIALLY_UNUSED (sk);

    bool grew (false);

    // index
    //
    if (j != 0)
    {
      bool is_null (false);
      sqlite::value_traits<
          index_type,
          sqlite::id_integer >::set_image (
        i.index_value,
        is_null,
        *j);
      i.index_null = is_null;
    }

    // value
    //
    {
      if (composite_value_traits< value_type, id_sqlite >::init (
            i.value_value,
            v,
            sk))
        grew = true;
    }

    if (grew)
      i.version++;
  }

  void access::object_traits_impl< ::bdep::configuration, id_sqlite >::packages_traits::
  init (index_type& j,
        value_type& v,
        const data_image_type& i,
        database* db)
  {
    ODB_POTENTIALLY_UNUSED (db);

    // index
    //
    {
      sqlite::value_traits<
          index_type,
          sqlite::id_integer >::set_value (
        j,
        i.index_value,
        i.index_null);
    }

    // value
    //
    {
      composite_value_traits< value_type, id_sqlite >::init (
        v,
        i.value_value,
        db);
    }
  }

  void access::object_traits_impl< ::bdep::configuration, id_sqlite >::packages_traits::
  insert (index_type i, 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, &i, 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< ::bdep::configuration, id_sqlite >::packages_traits::
  select (index_type& i, 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 (i, 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< ::bdep::configuration, id_sqlite >::packages_traits::
  delete_ (void* d)
  {
    using namespace sqlite;

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

  void access::object_traits_impl< ::bdep::configuration, id_sqlite >::packages_traits::
  persist (const container_type& c,
           statements_type& sts)
  {
    using namespace sqlite;

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

  void access::object_traits_impl< ::bdep::configuration, id_sqlite >::packages_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_ = true;
    container_traits_type::load (c, more, fs);
  }

  void access::object_traits_impl< ::bdep::configuration, id_sqlite >::packages_traits::
  update (const container_type& c,
          statements_type& sts)
  {
    using namespace sqlite;

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

  void access::object_traits_impl< ::bdep::configuration, id_sqlite >::packages_traits::
  erase (statements_type& sts)
  {
    using namespace sqlite;

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

  access::object_traits_impl< ::bdep::configuration, id_sqlite >::id_type
  access::object_traits_impl< ::bdep::configuration, id_sqlite >::
  id (const id_image_type& i)
  {
    sqlite::database* db (0);
    ODB_POTENTIALLY_UNUSED (db);

    id_type id;
    {
      sqlite::value_traits<
          ::bdep::optional_uint64_t,
          sqlite::id_integer >::set_value (
        id,
        i.id_value,
        i.id_null);
    }

    return id;
  }

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

    id_type id;
    {
      sqlite::value_traits<
          ::bdep::optional_uint64_t,
          sqlite::id_integer >::set_value (
        id,
        i.id_value,
        i.id_null);
    }

    return id;
  }

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

    bool grew (false);

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

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

    // type
    //
    if (t[2UL])
    {
      i.type_value.capacity (i.type_size);
      grew = true;
    }

    // path
    //
    if (t[3UL])
    {
      i.path_value.capacity (i.path_size);
      grew = true;
    }

    // relative_path
    //
    if (t[4UL])
    {
      i.relative_path_value.capacity (i.relative_path_size);
      grew = true;
    }

    // default_
    //
    t[5UL] = false;

    // forward
    //
    t[6UL] = false;

    // auto_sync
    //
    t[7UL] = false;

    return grew;
  }

  void access::object_traits_impl< ::bdep::configuration, 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::bind::integer;
      b[n].buffer = &i.id_value;
      b[n].is_null = &i.id_null;
      n++;
    }

    // name
    //
    b[n].type = sqlite::image_traits<
      ::bdep::optional_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++;

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

    // path
    //
    b[n].type = sqlite::image_traits<
      ::std::string,
      sqlite::id_text>::bind_value;
    b[n].buffer = i.path_value.data ();
    b[n].size = &i.path_size;
    b[n].capacity = i.path_value.capacity ();
    b[n].is_null = &i.path_null;
    n++;

    // relative_path
    //
    b[n].type = sqlite::image_traits<
      ::bdep::optional_string,
      sqlite::id_text>::bind_value;
    b[n].buffer = i.relative_path_value.data ();
    b[n].size = &i.relative_path_size;
    b[n].capacity = i.relative_path_value.capacity ();
    b[n].is_null = &i.relative_path_null;
    n++;

    // default_
    //
    b[n].type = sqlite::bind::integer;
    b[n].buffer = &i.default_value;
    b[n].is_null = &i.default_null;
    n++;

    // forward
    //
    b[n].type = sqlite::bind::integer;
    b[n].buffer = &i.forward_value;
    b[n].is_null = &i.forward_null;
    n++;

    // auto_sync
    //
    b[n].type = sqlite::bind::integer;
    b[n].buffer = &i.auto_sync_value;
    b[n].is_null = &i.auto_sync_null;
    n++;
  }

  void access::object_traits_impl< ::bdep::configuration, id_sqlite >::
  bind (sqlite::bind* b, id_image_type& i)
  {
    std::size_t n (0);
    b[n].type = sqlite::bind::integer;
    b[n].buffer = &i.id_value;
    b[n].is_null = &i.id_null;
  }

  bool access::object_traits_impl< ::bdep::configuration, 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)
    {
      ::bdep::optional_uint64_t const& v =
        o.id;

      bool is_null (false);
      sqlite::value_traits<
          ::bdep::optional_uint64_t,
          sqlite::id_integer >::set_image (
        i.id_value,
        is_null,
        v);
      i.id_null = is_null;
    }

    // name
    //
    {
      ::bdep::optional_string const& v =
        o.name;

      bool is_null (true);
      std::size_t cap (i.name_value.capacity ());
      sqlite::value_traits<
          ::bdep::optional_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 ());
    }

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

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

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

      // From project.hxx:41:14
      ::std::string const& vt =
        (v).string ();

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

    // relative_path
    //
    {
      ::bdep::optional_dir_path const& v =
        o.relative_path;

      // From project.hxx:44:14
      ::bdep::optional_string const& vt =
        (v) ? (v)->string () : bdep::optional_string ();

      bool is_null (true);
      std::size_t cap (i.relative_path_value.capacity ());
      sqlite::value_traits<
          ::bdep::optional_string,
          sqlite::id_text >::set_image (
        i.relative_path_value,
        i.relative_path_size,
        is_null,
        vt);
      i.relative_path_null = is_null;
      grew = grew || (cap != i.relative_path_value.capacity ());
    }

    // default_
    //
    {
      bool const& v =
        o.default_;

      bool is_null (false);
      sqlite::value_traits<
          bool,
          sqlite::id_integer >::set_image (
        i.default_value,
        is_null,
        v);
      i.default_null = is_null;
    }

    // forward
    //
    {
      bool const& v =
        o.forward;

      bool is_null (false);
      sqlite::value_traits<
          bool,
          sqlite::id_integer >::set_image (
        i.forward_value,
        is_null,
        v);
      i.forward_null = is_null;
    }

    // auto_sync
    //
    {
      bool const& v =
        o.auto_sync;

      bool is_null (false);
      sqlite::value_traits<
          bool,
          sqlite::id_integer >::set_image (
        i.auto_sync_value,
        is_null,
        v);
      i.auto_sync_null = is_null;
    }

    return grew;
  }

  void access::object_traits_impl< ::bdep::configuration, 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
    //
    {
      ::bdep::optional_uint64_t& v =
        o.id;

      sqlite::value_traits<
          ::bdep::optional_uint64_t,
          sqlite::id_integer >::set_value (
        v,
        i.id_value,
        i.id_null);
    }

    // name
    //
    {
      ::bdep::optional_string& v =
        o.name;

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

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

      sqlite::value_traits<
          ::std::string,
          sqlite::id_text >::set_value (
        v,
        i.type_value,
        i.type_size,
        i.type_null);
    }

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

      ::std::string vt;

      sqlite::value_traits<
          ::std::string,
          sqlite::id_text >::set_value (
        vt,
        i.path_value,
        i.path_size,
        i.path_null);

      // From project.hxx:41:14
      v = bdep::dir_path (vt);
    }

    // relative_path
    //
    {
      ::bdep::optional_dir_path& v =
        o.relative_path;

      ::bdep::optional_string vt;

      sqlite::value_traits<
          ::bdep::optional_string,
          sqlite::id_text >::set_value (
        vt,
        i.relative_path_value,
        i.relative_path_size,
        i.relative_path_null);

      // From project.hxx:44:14
      v = (vt) ? bdep::dir_path ( * (vt)) : bdep::optional_dir_path ();
    }

    // default_
    //
    {
      bool& v =
        o.default_;

      sqlite::value_traits<
          bool,
          sqlite::id_integer >::set_value (
        v,
        i.default_value,
        i.default_null);
    }

    // forward
    //
    {
      bool& v =
        o.forward;

      sqlite::value_traits<
          bool,
          sqlite::id_integer >::set_value (
        v,
        i.forward_value,
        i.forward_null);
    }

    // auto_sync
    //
    {
      bool& v =
        o.auto_sync;

      sqlite::value_traits<
          bool,
          sqlite::id_integer >::set_value (
        v,
        i.auto_sync_value,
        i.auto_sync_null);
    }
  }

  void access::object_traits_impl< ::bdep::configuration, id_sqlite >::
  init (id_image_type& i, const id_type& id)
  {
    {
      bool is_null (false);
      sqlite::value_traits<
          ::bdep::optional_uint64_t,
          sqlite::id_integer >::set_image (
        i.id_value,
        is_null,
        id);
      i.id_null = is_null;
    }
  }

  const char access::object_traits_impl< ::bdep::configuration, id_sqlite >::persist_statement[] =
  "INSERT INTO \"configuration\" "
  "(\"id\", "
  "\"name\", "
  "\"type\", "
  "\"path\", "
  "\"relative_path\", "
  "\"default\", "
  "\"forward\", "
  "\"auto_sync\") "
  "VALUES "
  "(?, ?, ?, ?, ?, ?, ?, ?)";

  const char access::object_traits_impl< ::bdep::configuration, id_sqlite >::find_statement[] =
  "SELECT "
  "\"configuration\".\"id\", "
  "\"configuration\".\"name\", "
  "\"configuration\".\"type\", "
  "\"configuration\".\"path\", "
  "\"configuration\".\"relative_path\", "
  "\"configuration\".\"default\", "
  "\"configuration\".\"forward\", "
  "\"configuration\".\"auto_sync\" "
  "FROM \"configuration\" "
  "WHERE \"configuration\".\"id\"=?";

  const char access::object_traits_impl< ::bdep::configuration, id_sqlite >::update_statement[] =
  "UPDATE \"configuration\" "
  "SET "
  "\"name\"=?, "
  "\"type\"=?, "
  "\"path\"=?, "
  "\"relative_path\"=?, "
  "\"default\"=?, "
  "\"forward\"=?, "
  "\"auto_sync\"=? "
  "WHERE \"id\"=?";

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

  const char access::object_traits_impl< ::bdep::configuration, id_sqlite >::query_statement[] =
  "SELECT "
  "\"configuration\".\"id\", "
  "\"configuration\".\"name\", "
  "\"configuration\".\"type\", "
  "\"configuration\".\"path\", "
  "\"configuration\".\"relative_path\", "
  "\"configuration\".\"default\", "
  "\"configuration\".\"forward\", "
  "\"configuration\".\"auto_sync\" "
  "FROM \"configuration\"";

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

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

  void access::object_traits_impl< ::bdep::configuration, id_sqlite >::
  persist (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> ());

    callback (db,
              static_cast<const object_type&> (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++;
    }

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

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

    obj.id = id (sts.id_image ());

    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 ());

    // packages
    //
    {
      ::std::vector< ::bdep::package_state > const& v =
        obj.packages;

      packages_traits::persist (
        v,
        esc.packages);
    }

    callback (db,
              static_cast<const object_type&> (obj),
              callback_event::post_persist);
  }

  void access::object_traits_impl< ::bdep::configuration, 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 ());

    // packages
    //
    {
      ::std::vector< ::bdep::package_state > const& v =
        obj.packages;

      packages_traits::update (
        v,
        esc.packages);
    }

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

  void access::object_traits_impl< ::bdep::configuration, 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 ());

    // packages
    //
    {
      packages_traits::erase (
        esc.packages);
    }

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

    pointer_cache_traits::erase (db, id);
  }

  access::object_traits_impl< ::bdep::configuration, id_sqlite >::pointer_type
  access::object_traits_impl< ::bdep::configuration, 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< ::bdep::configuration, 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< ::bdep::configuration, 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< ::bdep::configuration, 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< ::bdep::configuration, id_sqlite >::
  load_ (statements_type& sts,
         object_type& obj,
         bool reload)
  {
    ODB_POTENTIALLY_UNUSED (reload);

    extra_statement_cache_type& esc (sts.extra_statement_cache ());

    // packages
    //
    {
      ::std::vector< ::bdep::package_state >& v =
        obj.packages;

      packages_traits::load (
        v,
        esc.packages);
    }
  }

  result< access::object_traits_impl< ::bdep::configuration, id_sqlite >::object_type >
  access::object_traits_impl< ::bdep::configuration, 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< ::bdep::configuration, 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 ();
  }

  // configuration_count
  //

  bool access::view_traits_impl< ::bdep::configuration_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< ::bdep::configuration_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< ::bdep::configuration_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< ::bdep::configuration_count, id_sqlite >::query_base_type
  access::view_traits_impl< ::bdep::configuration_count, id_sqlite >::
  query_statement (const query_base_type& q)
  {
    query_base_type r (
      "SELECT "
      "COUNT(*) ");

    r += "FROM \"configuration\"";

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

    return r;
  }

  result< access::view_traits_impl< ::bdep::configuration_count, id_sqlite >::view_type >
  access::view_traits_impl< ::bdep::configuration_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);
  }
}

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 \"configuration_packages\"");
          db.execute ("DROP TABLE IF EXISTS \"configuration\"");
          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\" = ''");
          return false;
        }
      }
    }
    else
    {
      switch (pass)
      {
        case 1:
        {
          db.execute ("CREATE TABLE \"configuration\" (\n"
                      "  \"id\" INTEGER NULL PRIMARY KEY AUTOINCREMENT,\n"
                      "  \"name\" TEXT NULL,\n"
                      "  \"type\" TEXT NULL,\n"
                      "  \"path\" TEXT NULL,\n"
                      "  \"relative_path\" TEXT NULL,\n"
                      "  \"default\" INTEGER NULL,\n"
                      "  \"forward\" INTEGER NULL,\n"
                      "  \"auto_sync\" INTEGER NULL)");
          db.execute ("CREATE UNIQUE INDEX \"configuration_name_i\"\n"
                      "  ON \"configuration\" (\"name\")");
          db.execute ("CREATE UNIQUE INDEX \"configuration_path_i\"\n"
                      "  ON \"configuration\" (\"path\")");
          db.execute ("CREATE TABLE \"configuration_packages\" (\n"
                      "  \"object_id\" INTEGER NULL,\n"
                      "  \"index\" INTEGER NULL,\n"
                      "  \"name\" TEXT NULL COLLATE NOCASE,\n"
                      "  CONSTRAINT \"object_id_fk\"\n"
                      "    FOREIGN KEY (\"object_id\")\n"
                      "    REFERENCES \"configuration\" (\"id\")\n"
                      "    ON DELETE CASCADE)");
          db.execute ("CREATE INDEX \"configuration_packages_object_id_i\"\n"
                      "  ON \"configuration_packages\" (\"object_id\")");
          db.execute ("CREATE INDEX \"configuration_packages_index_i\"\n"
                      "  ON \"configuration_packages\" (\"index\")");
          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 ('', 2, 0)");
          return false;
        }
      }
    }

    return false;
  }

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

  static const schema_catalog_migrate_entry
  migrate_schema_entry_2_ (
    id_sqlite,
    "",
    2ULL,
    0);
}

#include <odb/post.hxx>
