d0e8cb22d6dc218b099bd06f41d96a5075475788
[framework/web/wrt-commons.git] / modules / db / include / dpl / db / thread_database_support.h
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16 /*
17  * @file    thread_database_support.h
18  * @author  Przemyslaw Dobrowolski (p.dobrowolsk)
19  * @version 1.0
20  * @brief   This file contains the declaration of thread database support
21  */
22
23 #ifndef DPL_THREAD_DATABASE_SUPPORT_H
24 #define DPL_THREAD_DATABASE_SUPPORT_H
25
26 #include <string>
27 #include <dpl/db/sql_connection.h>
28 #include <dpl/db/orm_interface.h>
29 #include <dpl/thread.h>
30 #include <dpl/assert.h>
31 #include <stdint.h>
32
33 namespace DPL
34 {
35 namespace DB
36 {
37
38 /**
39  * Thread database support
40  *
41  * Associate database connection with thread lifecycle
42  *
43  */
44
45 class ThreadDatabaseSupport :
46     public DPL::DB::ORM::IOrmInterface
47 {
48   private:
49     typedef DPL::DB::SqlConnection *SqlConnectionPtr;
50     typedef DPL::ThreadLocalVariable<SqlConnectionPtr> TLVSqlConnectionPtr;
51     typedef DPL::ThreadLocalVariable<size_t> TLVSizeT;
52     typedef DPL::ThreadLocalVariable<bool> TLVBool;
53
54     TLVSqlConnectionPtr m_connection;
55     TLVBool m_linger;
56     TLVSizeT m_refCounter;
57     TLVSizeT m_transactionDepth;
58     TLVSizeT m_attachCount;
59     TLVBool m_transactionCancel;
60     std::string m_address;
61     DPL::DB::SqlConnection::Flag::Type m_flags;
62
63     TLVSqlConnectionPtr &Connection()
64     {
65         return m_connection;
66     }
67
68     TLVBool &Linger()
69     {
70         return m_linger;
71     }
72
73     TLVSizeT &RefCounter()
74     {
75         return m_refCounter;
76     }
77
78     TLVSizeT &TransactionDepth()
79     {
80         return m_transactionDepth;
81     }
82
83     TLVSizeT &AttachCount()
84     {
85         return m_attachCount;
86     }
87
88     TLVBool &TransactionCancel()
89     {
90         return m_transactionCancel;
91     }
92
93     void CheckedConnectionDelete()
94     {
95         Assert(!Connection().IsNull());
96         Assert(*Linger() == true);
97
98         if (*RefCounter() > 0 || *AttachCount() > 0) {
99             return;
100         }
101
102         // Destroy connection
103         LogInfo("Destroying thread database connection: " << m_address);
104
105         delete *Connection();
106
107         // Blocking destroy
108         Connection().GuardValue(false);
109         Linger().GuardValue(false);
110         RefCounter().GuardValue(false);
111         TransactionCancel().GuardValue(false);
112         TransactionDepth().GuardValue(false);
113         AttachCount().GuardValue(false);
114
115         Connection().Reset();
116         Linger().Reset();
117         RefCounter().Reset();
118         TransactionCancel().Reset();
119         TransactionDepth().Reset();
120         AttachCount().Reset();
121     }
122
123     void TransactionUnref()
124     {
125         LogPedantic("Unref transaction");
126
127         if (--(*TransactionDepth()) == 0) {
128             LogPedantic("Transaction is finalized");
129
130             if (*TransactionCancel()) {
131                 LogPedantic("Transaction will be rolled back");
132                 (*Connection())->ExecCommand("ROLLBACK;");
133             } else {
134                 LogPedantic("Transaction will be commited");
135                 (*Connection())->ExecCommand("COMMIT;");
136             }
137         }
138     }
139
140   public:
141     ThreadDatabaseSupport(const std::string &address,
142                           DPL::DB::SqlConnection::Flag::Type flags) :
143         m_address(address),
144         m_flags(flags)
145     {
146     }
147
148     virtual ~ThreadDatabaseSupport()
149     {
150     }
151
152     void AttachToThread(
153                           DPL::DB::SqlConnection::Flag::Option options =
154                           DPL::DB::SqlConnection::Flag::RO)
155     {
156         Linger() = false;
157
158         if (!Connection().IsNull()) {
159             // Add reference
160             ++*AttachCount();
161             return;
162         }
163
164         // Initialize SQL connection described in traits
165         LogInfo("Attaching thread database connection: " << m_address);
166
167         Connection() = new DPL::DB::SqlConnection(m_address.c_str(), m_flags, options);
168
169         RefCounter() = 0;
170
171         AttachCount() = 1;
172
173         //Init Transaction related variables
174         TransactionDepth() = 0;
175         TransactionCancel() = false;
176
177         // Blocking destroy
178         Connection().GuardValue(true);
179         Linger().GuardValue(true);
180         RefCounter().GuardValue(true);
181         TransactionDepth().GuardValue(true);
182         AttachCount().GuardValue(true);
183         TransactionCancel().GuardValue(true);
184     }
185
186     void DetachFromThread()
187     {
188         // Calling thread must support thread database connections
189         Assert(!Connection().IsNull());
190
191         // Remove reference
192         --*AttachCount();
193
194         if (*AttachCount() > 0) {
195             return;
196         }
197
198         // It must not be in linger state yet
199         Assert(*Linger() == false);
200
201         LogInfo("Detaching thread database connection: " << m_address);
202
203         // Enter linger state
204         *Linger() = true;
205
206         // Checked delete
207         CheckedConnectionDelete();
208     }
209
210     bool IsAttached()
211     {
212         return !AttachCount().IsNull() && *AttachCount() > 0;
213     }
214
215     DPL::DB::SqlConnection::DataCommand *AllocDataCommand(
216             const std::string &statement)
217     {
218         // Calling thread must support thread database connections
219         Assert(!Connection().IsNull());
220
221         // Calling thread must not be in linger state
222         Assert(*Linger() == false);
223
224         // Add reference
225         ++*RefCounter();
226
227         // Create new unmanaged data command
228         return (*Connection())->PrepareDataCommand(statement.c_str()).release();
229     }
230
231     void FreeDataCommand(DPL::DB::SqlConnection::DataCommand *command)
232     {
233         // Calling thread must support thread database connections
234         Assert(!Connection().IsNull());
235
236         // Delete data command
237         delete command;
238
239         // Unreference SQL connection
240         --*RefCounter();
241
242         // If it is linger state, connection may be destroyed
243         if (*Linger() == true) {
244             CheckedConnectionDelete();
245         }
246     }
247
248     void TransactionBegin()
249     {
250         // Calling thread must support thread database connections
251         Assert(!Connection().IsNull());
252
253         LogPedantic("Begin transaction");
254
255         // Addref transaction
256         if (++(*TransactionDepth()) == 1) {
257             LogPedantic("Transaction is initialized");
258
259             TransactionCancel() = false;
260             (*Connection())->ExecCommand("BEGIN;");
261         }
262     }
263
264     void TransactionCommit()
265     {
266         // Calling thread must support thread database connections
267         Assert(!Connection().IsNull());
268
269         LogPedantic("Commit transaction");
270
271         // Unref transation
272         TransactionUnref();
273     }
274
275     void TransactionRollback()
276     {
277         // Calling thread must support thread database connections
278         Assert(!Connection().IsNull());
279
280         // Cancel and unref transaction
281         TransactionCancel() = true;
282         TransactionUnref();
283     }
284
285     DPL::DB::SqlConnection::RowID GetLastInsertRowID()
286     {
287         // Calling thread must support thread database connections
288         Assert(!Connection().IsNull());
289
290         return (*Connection())->GetLastInsertRowID();
291     }
292
293     bool CheckTableExist(const char *name)
294     {
295         // Calling thread must support thread database connections
296         Assert(!Connection().IsNull());
297
298         return (*Connection())->CheckTableExist(name);
299     }
300 };
301
302 }
303 }
304
305 #endif // DPL_THREAD_DATABASE_SUPPORT_H