aboutsummaryrefslogtreecommitdiff
path: root/odb/connection.cxx
blob: 14e89e2914dc333cd8ba0d6f3270ea7d8cd059bc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
// file      : odb/connection.cxx
// copyright : Copyright (c) 2009-2013 Code Synthesis Tools CC
// license   : GNU GPL v2; see accompanying LICENSE file

#include <odb/database.hxx>
#include <odb/connection.hxx>
#include <odb/result.hxx>
#include <odb/prepared-query.hxx>
#include <odb/exceptions.hxx> // prepared_*

using namespace std;

namespace odb
{
  connection::
  ~connection ()
  {
    assert (prepared_queries_ == 0);
    assert (prepared_map_.empty ());
  }

  void connection::
  clear_prepared_map ()
  {
    for (prepared_map_type::iterator i (prepared_map_.begin ()),
           e (prepared_map_.end ()); i != e; ++i)
    {
      if (i->second.params != 0)
        i->second.params_deleter (i->second.params);
    }

    prepared_map_.clear ();
  }

  void connection::
  recycle ()
  {
    while (prepared_queries_ != 0)
    {
      prepared_queries_->stmt.reset ();
      prepared_queries_->list_remove ();
    }
  }

  void connection::
  invalidate_results ()
  {
    while (results_ != 0)
    {
      results_->invalidate ();
      results_->list_remove ();
    }
  }

  void connection::
  cache_query_ (prepared_query_impl* pq,
                const type_info& ti,
                void* params,
                const type_info* params_info,
                void (*params_deleter) (void*))
  {
    pair<prepared_map_type::iterator, bool> r (
      prepared_map_.insert (
        prepared_map_type::value_type (pq->name, prepared_entry_type ())));

    if (!r.second)
      throw prepared_already_cached (pq->name);

    prepared_entry_type& e (r.first->second);

    // Mark this prepared query as cached , get its ref count to 1
    // (prepared_query instances now reference this impl object),
    // and remove it from the invalidation list.
    //
    pq->cached = true;

    while (pq->_ref_count () > 1)
      pq->_dec_ref ();

    pq->list_remove ();

    e.prep_query.reset (pq);
    e.type_info = &ti;
    e.params = params;
    e.params_info = params_info;
    e.params_deleter = params_deleter;
  }

  prepared_query_impl* connection::
  lookup_query_ (const char* name,
                 const type_info& ti,
                 void** params,
                 const type_info* params_info) const
  {
    prepared_map_type::const_iterator i (prepared_map_.find (name));

    if (i == prepared_map_.end ())
    {
      // Use a factory, if there is one.
      //
      if (database_.call_query_factory (name,
                                        const_cast<connection&> (*this)))
        i = prepared_map_.find (name);
    }

    if (i == prepared_map_.end ())
      return 0;

    // Make sure the types match.
    //
    if (*i->second.type_info != ti)
      throw prepared_type_mismatch (name);

    if (params != 0)
    {
      if (*i->second.params_info != *params_info)
        throw prepared_type_mismatch (name);

      *params = i->second.params;
    }

    return i->second.prep_query.get ();
  }
}