|
1 /* |
|
2 * Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: StorageDBHandler |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 #include <sstream> |
|
20 #include <sqlite3.h> |
|
21 #include <stdlib.h> |
|
22 #include <vector> |
|
23 |
|
24 #include "javacommonutils.h" |
|
25 #include "javastoragenames.h" |
|
26 #include "javastoragetables.h" |
|
27 #include "logger.h" |
|
28 #include "storagedbhandler.h" |
|
29 |
|
30 using namespace java::storage; |
|
31 using namespace java::util; |
|
32 using namespace std; |
|
33 |
|
34 StorageDBHandler::StorageDBHandler() |
|
35 { |
|
36 JELOG2(EJavaStorage); |
|
37 iDb = 0; |
|
38 iResultString = L""; |
|
39 mHavingTransaction = false; |
|
40 } |
|
41 |
|
42 StorageDBHandler::~StorageDBHandler() |
|
43 { |
|
44 JELOG2(EJavaStorage); |
|
45 |
|
46 // close and and remove all open sessions from DB list |
|
47 for (iDbListIter = iDbList.begin(); |
|
48 iDbListIter != iDbList.end(); |
|
49 iDbListIter++) |
|
50 { |
|
51 if ((*iDbListIter).second != 0) |
|
52 { |
|
53 sqlite3_close((*iDbListIter).second); |
|
54 } |
|
55 } |
|
56 iDbList.clear(); |
|
57 } |
|
58 |
|
59 int StorageDBHandler::open(const wstring& aDbName) |
|
60 { |
|
61 JELOG2(EJavaStorage); |
|
62 mHavingTransaction = false; |
|
63 char* dbnameAsChar = 0; |
|
64 |
|
65 try |
|
66 { |
|
67 dbnameAsChar = JavaCommonUtils::wstringToUtf8(aDbName); |
|
68 } |
|
69 catch (ExceptionBase& eb) |
|
70 { |
|
71 ELOG1(EJavaStorage, "UTF8 conversion error: %s", eb.toString().c_str()); |
|
72 return -1; |
|
73 } |
|
74 |
|
75 // Create a random session id number for the connection |
|
76 wstring sessionID = JavaCommonUtils::intToWstring(rand()); |
|
77 sessionID += JavaCommonUtils::intToWstring(rand()); |
|
78 int rc = sqlite3_open(dbnameAsChar, &iDb); |
|
79 |
|
80 if (rc) |
|
81 { |
|
82 ELOG1(EJavaStorage, "Cannot open database: %s", |
|
83 sqlite3_errmsg(iDb)); |
|
84 sqlite3_close(iDb); |
|
85 delete[] dbnameAsChar; |
|
86 return rc; |
|
87 } |
|
88 else |
|
89 { |
|
90 iCurrentSession.first = sessionID; |
|
91 iCurrentSession.second = iDb; |
|
92 iDbList.push_back(iCurrentSession); |
|
93 } |
|
94 |
|
95 if (!isDBInitialized(dbnameAsChar)) |
|
96 { |
|
97 LOG(EJavaStorage, EInfo, "Initializing DB."); |
|
98 try |
|
99 { |
|
100 initializeDatabase(dbnameAsChar); |
|
101 LOG(EJavaStorage, EInfo, "DB initialized OK."); |
|
102 } |
|
103 catch (JavaStorageException& jse) |
|
104 { |
|
105 ELOG1(EJavaStorage, |
|
106 "Init failed: %s", |
|
107 jse.toString().c_str()); |
|
108 rc = EInternalError; |
|
109 } |
|
110 } |
|
111 |
|
112 delete[] dbnameAsChar; |
|
113 return rc; |
|
114 } |
|
115 |
|
116 int StorageDBHandler::close() |
|
117 { |
|
118 JELOG2(EJavaStorage); |
|
119 |
|
120 // If active transaction while closing connection. Rollback is done |
|
121 // to maintain DB consistency. |
|
122 if (mHavingTransaction) |
|
123 { |
|
124 WLOG(EJavaStorage, |
|
125 "Close while active session. Doing rollback"); |
|
126 int err = rollback(); |
|
127 if (err < 0) |
|
128 { |
|
129 WLOG1(EJavaStorage, "Rollback failed: %d", err); |
|
130 } |
|
131 } |
|
132 |
|
133 int rc = sqlite3_close(iDb); |
|
134 |
|
135 // remove the session connection object from the connections list |
|
136 for (iDbListIter = iDbList.begin(); |
|
137 iDbListIter != iDbList.end(); |
|
138 ++iDbListIter) |
|
139 { |
|
140 if (iCurrentSession.first == (*iDbListIter).first) |
|
141 { |
|
142 iDbList.erase(iDbListIter++); |
|
143 break; |
|
144 } |
|
145 } |
|
146 return rc; |
|
147 } |
|
148 |
|
149 int StorageDBHandler::startTransaction() |
|
150 { |
|
151 JELOG2(EJavaStorage); |
|
152 int rc = 0; |
|
153 string statement = "BEGIN;"; |
|
154 try |
|
155 { |
|
156 executeStandalone(statement); |
|
157 mHavingTransaction = true; |
|
158 } |
|
159 catch (JavaStorageException& jse) |
|
160 { |
|
161 rc = jse.mStatus; |
|
162 mHavingTransaction = false; |
|
163 ELOG1(EJavaStorage, |
|
164 "Transaction start failed: %s", |
|
165 jse.toString().c_str()); |
|
166 } |
|
167 |
|
168 return rc; |
|
169 } |
|
170 |
|
171 int StorageDBHandler::prepare(const std::wstring& aMessage) |
|
172 { |
|
173 JELOG2(EJavaStorage); |
|
174 int rc; |
|
175 const char *tail = 0; |
|
176 int statementBytes = aMessage.length() * 4; |
|
177 char *zErrMsg = 0; |
|
178 char* stmAsChar = 0; |
|
179 |
|
180 try |
|
181 { |
|
182 stmAsChar = JavaCommonUtils::wstringToUtf8(aMessage); |
|
183 } |
|
184 catch (ExceptionBase& eb) |
|
185 { |
|
186 ELOG1(EJavaStorage, "UTF8 conversion error: %s", eb.toString().c_str()); |
|
187 return -1; |
|
188 } |
|
189 |
|
190 rc = sqlite3_prepare_v2( |
|
191 iDb, stmAsChar, statementBytes , &iStatement, &tail); |
|
192 |
|
193 |
|
194 if (SQLITE_OK != rc) |
|
195 { |
|
196 ELOG1(EJavaStorage, "SQL error on prepare: %d", rc); |
|
197 sqlite3_free(zErrMsg); |
|
198 delete [] stmAsChar; |
|
199 return rc; |
|
200 } |
|
201 |
|
202 delete [] stmAsChar; |
|
203 |
|
204 return rc; |
|
205 } |
|
206 |
|
207 std::wstring& StorageDBHandler::executeStmt() |
|
208 { |
|
209 JELOG2(EJavaStorage); |
|
210 int rc; |
|
211 iResultString.clear(); |
|
212 std::wostringstream oss; |
|
213 |
|
214 rc = sqlite3_step(iStatement); |
|
215 |
|
216 while (SQLITE_ROW == rc) |
|
217 { |
|
218 const char *columnName(0); |
|
219 const unsigned char *column(0); |
|
220 oss << L";#\n;"; |
|
221 |
|
222 for (int i = 0; i < sqlite3_column_count(iStatement); i++) |
|
223 { |
|
224 column = sqlite3_column_text(iStatement, i); |
|
225 |
|
226 if (column) |
|
227 { |
|
228 wstring columnValue = JavaCommonUtils::utf8ToWstring( |
|
229 reinterpret_cast<const char*>(column)); |
|
230 |
|
231 columnName = sqlite3_column_name(iStatement, i); |
|
232 oss << JavaCommonUtils::utf8ToWstring(columnName); |
|
233 oss << L"=" + columnValue + L";\n;"; |
|
234 } |
|
235 } |
|
236 rc = sqlite3_step(iStatement); |
|
237 } |
|
238 |
|
239 iResultString = oss.str(); |
|
240 |
|
241 // Return affected rowCount if no other content to be returned. |
|
242 // This is to return e.g. how many rows removed from DB using DELETE |
|
243 // statement. |
|
244 if (L"" == iResultString) |
|
245 { |
|
246 int changes = sqlite3_changes(iDb); |
|
247 iResultString = JavaCommonUtils::intToWstring(changes); |
|
248 } |
|
249 |
|
250 // Same statement is not reused. |
|
251 int fc = sqlite3_finalize(iStatement); |
|
252 if (0 != fc) |
|
253 { |
|
254 WLOG1(EJavaStorage, "Finalize failed: %d", fc); |
|
255 } |
|
256 |
|
257 return iResultString; |
|
258 } |
|
259 |
|
260 int StorageDBHandler::commit() |
|
261 { |
|
262 JELOG2(EJavaStorage); |
|
263 int rc = 0; |
|
264 string statement = "COMMIT;"; |
|
265 try |
|
266 { |
|
267 executeStandalone(statement); |
|
268 mHavingTransaction = false; |
|
269 } |
|
270 catch (JavaStorageException& jse) |
|
271 { |
|
272 rc = jse.mStatus; |
|
273 ELOG1(EJavaStorage, |
|
274 "Transaction commit failed: %s", |
|
275 jse.toString().c_str()); |
|
276 } |
|
277 |
|
278 return rc; |
|
279 } |
|
280 |
|
281 int StorageDBHandler::rollback() |
|
282 { |
|
283 JELOG2(EJavaStorage); |
|
284 int rc = 0; |
|
285 string statement = "ROLLBACK;"; |
|
286 try |
|
287 { |
|
288 executeStandalone(statement); |
|
289 mHavingTransaction = false; |
|
290 } |
|
291 catch (JavaStorageException& jse) |
|
292 { |
|
293 rc = jse.mStatus; |
|
294 ELOG1(EJavaStorage, |
|
295 "Transaction rollback failed: %s", |
|
296 jse.toString().c_str()); |
|
297 } |
|
298 |
|
299 return rc; |
|
300 } |
|
301 |
|
302 bool StorageDBHandler::selectConnection(const wstring& aSessionID) |
|
303 { |
|
304 JELOG2(EJavaStorage); |
|
305 for (iDbListIter = iDbList.begin(); |
|
306 iDbListIter != iDbList.end(); |
|
307 iDbListIter++) |
|
308 { |
|
309 iCurrentSession = *iDbListIter; |
|
310 if (iCurrentSession.first == aSessionID) |
|
311 { |
|
312 iDb = iCurrentSession.second; |
|
313 return true; |
|
314 } |
|
315 } |
|
316 return false; |
|
317 } |
|
318 |
|
319 wstring StorageDBHandler::returnSessionID() |
|
320 { |
|
321 return iCurrentSession.first; |
|
322 } |
|
323 |
|
324 bool StorageDBHandler::isDBInitialized(const string& aDbName) |
|
325 { |
|
326 JELOG2(EJavaStorage); |
|
327 bool result = false; |
|
328 |
|
329 string sqlCommand = "SELECT ID FROM "; |
|
330 |
|
331 if (JAVA_DATABASE_NAME == aDbName) |
|
332 { |
|
333 sqlCommand.append(APPLICATION_PACKAGE_TABLE); |
|
334 } |
|
335 else if (JAVA_OTA_DATABASE_NAME == aDbName) |
|
336 { |
|
337 sqlCommand.append(OTA_STATUS_TABLE); |
|
338 } |
|
339 else |
|
340 { |
|
341 // Only predefined databases are supported. |
|
342 return result; |
|
343 } |
|
344 |
|
345 sqlCommand.append(";"); |
|
346 |
|
347 try |
|
348 { |
|
349 executeStandalone(sqlCommand); |
|
350 result = true; |
|
351 } |
|
352 catch (JavaStorageException& jse) |
|
353 { |
|
354 WLOG1(EJavaStorage, "DB not init: %s", jse.toString().c_str()); |
|
355 } |
|
356 return result; |
|
357 } |
|
358 |
|
359 void StorageDBHandler::initializeDatabase(const string& aDbName) |
|
360 throw(JavaStorageException) |
|
361 { |
|
362 JELOG2(EJavaStorage); |
|
363 |
|
364 if (JAVA_DATABASE_NAME == aDbName) |
|
365 { |
|
366 // Create java database tables. |
|
367 executeStandalone(APPLICATION_PACKAGE); |
|
368 executeStandalone(APPLICATION); |
|
369 executeStandalone(APPLICATION_PACKAGE_ATTRIBUTES); |
|
370 executeStandalone(MIDP_PACKAGE); |
|
371 executeStandalone(MIDP_PERMISSIONS); |
|
372 executeStandalone(MIDP_FUNC_GRP_SETTINGS); |
|
373 executeStandalone(PUSH_REGISTRATIONS); |
|
374 executeStandalone(ALARM_REGISTRATIONS); |
|
375 executeStandalone(RUNTIME_SETTINGS); |
|
376 executeStandalone(PREINSTALL); |
|
377 } |
|
378 else if (JAVA_OTA_DATABASE_NAME == aDbName) |
|
379 { |
|
380 // Create OTA database table. |
|
381 executeStandalone(OTA_STATUS); |
|
382 } |
|
383 else |
|
384 { |
|
385 // Only predefined database init is supported. No error thrown as |
|
386 // db open is still success. |
|
387 } |
|
388 } |
|
389 |
|
390 void StorageDBHandler::executeStandalone(const string& aStatement) |
|
391 throw(JavaStorageException) |
|
392 { |
|
393 JELOG2(EJavaStorage); |
|
394 |
|
395 char *zErrMsg = 0; |
|
396 int rc = -1; |
|
397 |
|
398 rc = sqlite3_exec(iDb, aStatement.c_str(), dBCallback, 0, &zErrMsg); |
|
399 |
|
400 if (SQLITE_OK != rc) |
|
401 { |
|
402 ELOG2(EJavaStorage, "Db error code: %d msg: %s", rc, zErrMsg); |
|
403 string errString(zErrMsg); |
|
404 |
|
405 sqlite3_free(zErrMsg); |
|
406 |
|
407 throw JavaStorageException(rc, |
|
408 errString.c_str(), |
|
409 __FILE__, |
|
410 __FUNCTION__, |
|
411 __LINE__); |
|
412 } |
|
413 } |
|
414 |
|
415 int StorageDBHandler::dBCallback(void */*NotUsed*/, |
|
416 int argc, |
|
417 char **argv, |
|
418 char **azColName) |
|
419 { |
|
420 JELOG2(EJavaStorage); |
|
421 for (int i = 0; i < argc; i++) |
|
422 { |
|
423 ELOG2(EJavaStorage, " %s = %s", |
|
424 azColName[i], argv[i] ? argv[i] : "NULL"); |
|
425 } |
|
426 return 0; |
|
427 } |
|
428 |
|
429 const char* StorageDBHandler::getErrorMessage() |
|
430 { |
|
431 JELOG2(EJavaStorage); |
|
432 return sqlite3_errmsg(iDb); |
|
433 } |
|
434 |
|
435 int StorageDBHandler::getErrorCode() |
|
436 { |
|
437 JELOG2(EJavaStorage); |
|
438 return sqlite3_errcode(iDb); |
|
439 } |