Fix the boiler plate codes
[platform/framework/native/appfw.git] / src / io / FIo_DbEnumeratorImpl.cpp
1 //
2 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
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 /**
18  * @file        FIo_DbEnumeratorImpl.cpp
19  * @brief       This is the implementation file for _DbEnumeratorImpl class.
20  */
21
22 #include <stdio.h>
23 #include <semaphore.h>
24 #include <errno.h>
25 #include <unique_ptr.h>
26 #include <sqlite3.h>
27
28 #include <FBaseInteger.h>
29 #include <FBaseDouble.h>
30 #include <FBaseString.h>
31 #include <FBaseByteBuffer.h>
32 #include <FBaseDateTime.h>
33 #include <FBaseUtilStringUtil.h>
34 #include <FBaseColLinkedList.h>
35 #include <FBaseColArrayList.h>
36 #include <FBaseColIEnumerator.h>
37 #include <FBaseSysLog.h>
38
39 #include <FBase_NativeError.h>
40 #include <FApp_AppInfo.h>
41 #include <FSys_RuntimeInfoImpl.h>
42 #include <FIo_DbEnumeratorImpl.h>
43
44 using namespace std;
45 using namespace Tizen::Base;
46 using namespace Tizen::Base::Utility;
47 using namespace Tizen::Base::Runtime;
48 using namespace Tizen::System;
49 using namespace Tizen::App;
50 using namespace Tizen::Base::Collection;
51
52 namespace Tizen { namespace Io
53 {
54 static const unsigned int _MAX_DB_CACHE_SIZE = 2 * 1024 * 1024; // default cache size is 2MB
55
56 class _DbRow
57         : public Object
58 {
59 public:
60         _DbRow(void);
61         ~_DbRow(void);
62         LinkedList dbValuesList;
63         bool hasData;
64         int dataSize;
65 };
66
67 _DbRow::_DbRow(void)
68         : hasData(false)
69         , dataSize(0)
70 {
71 }
72
73 _DbRow::~_DbRow(void)
74 {
75         if (this->hasData == true)
76         {
77                 dbValuesList.RemoveAll(true);
78         }
79 }
80
81 class _DbColumn
82         : public Object
83 {
84 public:
85         _DbColumn(void);
86         ~_DbColumn(void);
87         int type;
88         int size;
89         unique_ptr<char[]> pData;
90 };
91
92 _DbColumn::_DbColumn(void)
93         : type(SQLITE_NULL)
94         , size(0)
95         , pData(null)
96 {
97 }
98
99 _DbColumn::~_DbColumn(void)
100 {
101 }
102
103 class _DbEnumeratorCache
104         : public Object
105 {
106 private:
107         /**
108         * This is the default constructor for this class.
109         */
110         _DbEnumeratorCache(void);
111         ~_DbEnumeratorCache(void);
112
113         unsigned int __currentUsedMemory;
114         _DbRow* __pCurrentDbRow;
115         LinkedList __dbColumnNameList;
116         LinkedList __dbRowList;
117
118         friend class _DbEnumeratorImpl;
119
120 };
121
122 _DbEnumeratorCache::_DbEnumeratorCache(void)
123         : __currentUsedMemory(0)
124         , __pCurrentDbRow(null)
125 {
126 }
127
128 _DbEnumeratorCache::~_DbEnumeratorCache(void)
129 {
130         __dbColumnNameList.RemoveAll(true);
131         __dbRowList.RemoveAll(true);
132 }
133
134 _DbEnumeratorImpl::_DbEnumeratorImpl(void)
135         : __shouldReleaseResource(false)
136         , __pEnum(null)
137         , __pDatabase(null)
138         , __columnCount(0)
139         , __rowCount(0)
140         , __currentRowIndex(-1)
141         , __pDbEnumeratorCache(null)
142 {
143 }
144
145 _DbEnumeratorImpl::~_DbEnumeratorImpl(void)
146 {
147         result r = E_SUCCESS;
148         int ret = 0;
149
150         if (__shouldReleaseResource && __pEnum)
151         {
152                 ret = sqlite3_finalize(static_cast <sqlite3_stmt*>(__pEnum));
153                 if (ret != SQLITE_OK)
154                 {
155                         r = __ConvertNativeSqliteErrorToResult(ret);
156                         SysLog(NID_IO, "[%s] Failed to finalize SQL statement (%d, %s).", GetErrorMessage(
157                                                         r), ret, sqlite3_errmsg((sqlite3*) __pDatabase));
158                 }
159         }
160
161         delete __pDbEnumeratorCache;
162 }
163
164 result
165 _DbEnumeratorImpl::CacheRow(bool cacheColumnNamesToo)
166 {
167         SysTryReturnResult(NID_IO, __pEnum != null, E_INVALID_STATE,
168                         "The Object is not constructed or the database is already been closed.");
169         SysTryReturnResult(NID_IO, __pDbEnumeratorCache != null, E_INVALID_STATE,
170                         "The Object is not constructed or the database is already been closed.");
171
172         int ret = 0;
173         result r = E_SUCCESS;
174
175         // check if all the rows are been cached already
176         if (__rowCount > 0)
177         {
178                 SysTryReturnResult(NID_IO, __currentRowIndex < (__rowCount - 1), E_OUT_OF_RANGE,
179                                         "Reached to the end of the result set.");
180         }
181
182         ret = sqlite3_step((sqlite3_stmt*) __pEnum);
183         switch (ret)
184         {
185         case SQLITE_DONE:
186         {
187                 // set max rows in the result set
188                 if (__currentRowIndex >= 0)
189                 {
190                         __rowCount = __currentRowIndex + 1;
191                 }
192                 return E_OUT_OF_RANGE;
193         }
194         case SQLITE_ROW:
195         {
196                 int dbRowSize = 0;
197                 unique_ptr<_DbRow> pDbRow(new (std::nothrow) _DbRow);
198                 SysTryReturnResult(NID_IO, pDbRow != null, E_OUT_OF_MEMORY, "The memory is insufficient.");
199
200                 for (int i = 0; i < __columnCount; i++)
201                 {
202                         // prepare column name list only once
203                         if (cacheColumnNamesToo == true)
204                         {
205                                 // get column name
206                                 const char* pName = sqlite3_column_name((sqlite3_stmt*) __pEnum, i);
207
208                                 r = __pDbEnumeratorCache->__dbColumnNameList.Add(* new (std::nothrow) String(pName));
209                                 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Propagated.", GetErrorMessage(r));
210                         }
211
212                         unique_ptr<_DbColumn> pDbColumn(new (std::nothrow) _DbColumn);
213                         SysTryReturnResult(NID_IO, pDbColumn != null, E_OUT_OF_MEMORY,
214                                         "The memory is insufficient.");
215
216                         int columnType = sqlite3_column_type((sqlite3_stmt*) __pEnum, i);
217
218                         pDbColumn->type = columnType;
219
220                         switch (columnType)
221                         {
222                         case SQLITE_INTEGER:
223                         {
224                                 int size = sizeof(long long);
225                                 unique_ptr<char[]> pData(new (std::nothrow) char[size + 1]);
226                                 SysTryReturnResult(NID_IO, pData != null, E_OUT_OF_MEMORY,
227                                                 "The memory is insufficient.");
228                                 memset(pData.get(), 0, size + 1);
229                                 long long value = sqlite3_column_int64((sqlite3_stmt*) __pEnum, i);
230                                 memcpy(pData.get(), &value, size);
231                                 pDbColumn->size = size;
232                                 pDbColumn->pData = move(pData);
233                                 break;
234                         }
235                         case SQLITE_FLOAT:
236                         {
237                                 int size = sizeof(double);
238                                 unique_ptr<char[]> pData(new (std::nothrow) char[size + 1]);
239                                 SysTryReturnResult(NID_IO, pData != null, E_OUT_OF_MEMORY,
240                                                 "The memory is insufficient.");
241                                 memset(pData.get(), 0, size + 1);
242                                 double doubleValue = sqlite3_column_double((sqlite3_stmt*) __pEnum, i);
243                                 memcpy(pData.get(), &doubleValue, size);
244                                 pDbColumn->size = size;
245                                 pDbColumn->pData = move(pData);
246                                 break;
247                         }
248                         case SQLITE_TEXT:
249                         {
250                                 int size = sqlite3_column_bytes((sqlite3_stmt*) __pEnum, i);
251                                 unique_ptr<char[]> pData(new (std::nothrow) char[size + 1]);
252                                 SysTryReturnResult(NID_IO, pData != null, E_OUT_OF_MEMORY,
253                                                 "The memory is insufficient.");
254                                 memset(pData.get(), 0, size + 1);
255                                 char* pTextData = (char*) sqlite3_column_text((sqlite3_stmt*) __pEnum, i);
256                                 memcpy(pData.get(), pTextData, size);
257                                 pDbColumn->size = size;
258                                 pDbColumn->pData = move(pData);
259                                 break;
260                         }
261                         case SQLITE_BLOB:
262                         {
263                                 int size = sqlite3_column_bytes((sqlite3_stmt*) __pEnum, i);
264                                 unique_ptr<char[]> pData(new (std::nothrow) char[size + 1]);
265                                 SysTryReturnResult(NID_IO, pData != null, E_OUT_OF_MEMORY,
266                                                 "The memory is insufficient.");
267                                 memset(pData.get(), 0, size + 1);
268                                 char* pBlobData = (char*) sqlite3_column_blob((sqlite3_stmt*) __pEnum, i);
269                                 memcpy(pData.get(), pBlobData, size);
270                                 pDbColumn->size = size;
271                                 pDbColumn->pData = move(pData);
272                                 break;
273                         }
274                         case SQLITE_NULL:
275                         {
276                                 int size = sqlite3_column_bytes((sqlite3_stmt*) __pEnum, i);
277                                 pDbColumn->size = size;
278                                 break;
279                         }
280                         default:
281                         {
282                                 SysTryReturnResult(NID_IO, false, E_DATABASE, "The column type is invalid.");
283                                 break;
284                         }
285                         }
286                         dbRowSize += pDbColumn->size;
287                         r = pDbRow->dbValuesList.Add(*pDbColumn.release());
288                         SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Propagated.", GetErrorMessage(r));
289                 }
290
291                 __pDbEnumeratorCache->__currentUsedMemory += dbRowSize;
292
293                 if (__pDbEnumeratorCache->__currentUsedMemory > _MAX_DB_CACHE_SIZE)
294                 {
295                         // remove old rows in FIFO manner till there is enough space for the current row.
296                         for (int i = 0; i < __pDbEnumeratorCache->__dbRowList.GetCount(); i++)
297                         {
298                                 _DbRow* pTmpDbRow = dynamic_cast< _DbRow* >(__pDbEnumeratorCache->__dbRowList.GetAt(i));
299                                 SysTryReturn(NID_IO, pTmpDbRow != null, GetLastResult(), GetLastResult(), "[%s] Propagated.", GetErrorMessage(GetLastResult()));
300                                 if (pTmpDbRow->hasData == true)
301                                 {
302                                         pTmpDbRow->dbValuesList.RemoveAll(true);
303                                         pTmpDbRow->hasData = false;
304                                         __pDbEnumeratorCache->__currentUsedMemory -= pTmpDbRow->dataSize;
305                                         pTmpDbRow->dataSize = 0;
306
307                                         if (__pDbEnumeratorCache->__currentUsedMemory <= _MAX_DB_CACHE_SIZE)
308                                         {
309                                                 break;
310                                         }
311                                 }
312                         }
313                 }
314
315                 pDbRow->hasData = true;
316                 pDbRow->dataSize = dbRowSize;
317                 _DbRow* pTmpDbRow = pDbRow.release();
318                 r = __pDbEnumeratorCache->__dbRowList.Add(*pTmpDbRow);
319                 if (IsFailed(r))
320                 {
321                         pTmpDbRow->dbValuesList.RemoveAll(true);
322                         delete pTmpDbRow;
323                         SysLog(NID_IO, "[%s] Propagated.", GetErrorMessage(r));
324                         return r;
325                 }
326
327                 ++__currentRowIndex;
328
329                 // set current cursor
330                 __pDbEnumeratorCache->__pCurrentDbRow = pTmpDbRow;
331
332                 break;
333         }
334         default:
335         {
336                 if (!_AppInfo::IsOspCompat())
337                 {
338                         r = __ConvertNativeSqliteErrorToDetailResult(ret);
339                         switch (r)
340                         {
341                         case E_INVALID_ARG:
342                         case E_ILLEGAL_ACCESS:
343                         case E_STORAGE_FULL:
344                         case E_INVALID_OPERATION:
345                         case E_UNKNOWN:
346                                 r = E_SYSTEM;
347                                 break;
348                         }
349                 }
350                 else
351                 {
352                         r = __ConvertNativeSqliteErrorToResult(ret);
353                 }
354
355                 SysLog(NID_IO, "[%s] Failed to move row index. (%d, %s).", GetErrorMessage(r), ret,
356                                 sqlite3_errmsg(static_cast< sqlite3* >(__pDatabase)));
357
358                 return r;
359         }
360         }
361
362         return E_SUCCESS;
363 }
364
365 result
366 _DbEnumeratorImpl::CacheRow(_DbRow& dbRow, int rowIndex)
367 {
368         result r = E_SUCCESS;
369         int ret = 0;
370
371         SysTryReturnResult(NID_IO, __pEnum != null, E_INVALID_STATE,
372                                 "The Object is not constructed or the database is already been closed.");
373
374         SysTryReturnResult(NID_IO, __pDbEnumeratorCache != null, E_INVALID_STATE,
375                                 "The Object is not constructed or the database is already been closed.");
376
377         // reset sqlite result set.
378         ret = sqlite3_reset((sqlite3_stmt*) __pEnum);
379         if (ret != SQLITE_OK)
380         {
381                 if (!_AppInfo::IsOspCompat())
382                 {
383                         r = __ConvertNativeSqliteErrorToDetailResult(ret);
384                         switch (ret)
385                         {
386                                 case E_INVALID_ARG:
387                                 case E_ILLEGAL_ACCESS:
388                                 case E_IO:
389                                 case E_INVALID_FORMAT:
390                                 case E_STORAGE_FULL:
391                                 case E_INVALID_OPERATION:
392                                 case E_UNKNOWN:
393                                         r = E_SYSTEM;
394                                         break;
395                         }
396                 }
397                 else
398                 {
399                         r = __ConvertNativeSqliteErrorToResult(ret);
400                 }
401
402                 SysLog(NID_IO, "[%s] Failed to reset SQL statement. (%d, %s).", GetErrorMessage(r),
403                         ret, sqlite3_errmsg(static_cast< sqlite3* >(__pDatabase)));
404                 return r;
405         }
406
407         // move cursor to desired position.
408         for (int i = 0; i <= rowIndex; i++)
409         {
410                 ret = sqlite3_step((sqlite3_stmt*) __pEnum);
411                 if (ret != SQLITE_ROW)
412                 {
413                         SysLog(NID_IO, "Did not yield any result row");
414                         return E_DATABASE;
415                 }
416         }
417
418         // ret == SQLITE_ROW, cache the row.
419         int dbRowSize = 0;
420
421         for (int i = 0; i < __columnCount; i++)
422         {
423                 unique_ptr<_DbColumn> pDbColumn(new (std::nothrow) _DbColumn);
424                 SysTryReturnResult(NID_IO, pDbColumn != null, E_OUT_OF_MEMORY, "The memory is insufficient.");
425
426                 int columnType = sqlite3_column_type((sqlite3_stmt*) __pEnum, i);
427
428                 pDbColumn->type = columnType;
429
430                 switch (columnType)
431                 {
432                 case SQLITE_INTEGER:
433                 {
434                         int size = sizeof(long long);
435                         unique_ptr<char[]> pData(new (std::nothrow) char[size + 1]);
436                         SysTryReturnResult(NID_IO, pData != null, E_OUT_OF_MEMORY, "The memory is insufficient.");
437                         memset(pData.get(), 0, size + 1);
438                         long long value = sqlite3_column_int64((sqlite3_stmt*) __pEnum, i);
439                         memcpy(pData.get(), &value, size);
440                         pDbColumn->size = size;
441                         pDbColumn->pData = move(pData);
442                         break;
443                 }
444                 case SQLITE_FLOAT:
445                 {
446                         int size = sizeof(double);
447                         unique_ptr<char[]> pData(new (std::nothrow) char[size + 1]);
448                         SysTryReturnResult(NID_IO, pData != null, E_OUT_OF_MEMORY, "The memory is insufficient.");
449                         memset(pData.get(), 0, size + 1);
450                         double doubleValue = sqlite3_column_double((sqlite3_stmt*) __pEnum, i);
451                         memcpy(pData.get(), &doubleValue, size);
452                         pDbColumn->size = size;
453                         pDbColumn->pData = move(pData);
454                         break;
455                 }
456                 case SQLITE_TEXT:
457                 {
458                         int size = sqlite3_column_bytes((sqlite3_stmt*) __pEnum, i);
459                         unique_ptr<char[]> pData(new (std::nothrow) char[size + 1]);
460                         SysTryReturnResult(NID_IO, pData != null, E_OUT_OF_MEMORY, "The memory is insufficient.");
461                         memset(pData.get(), 0, size + 1);
462                         char* pTextData = (char*) sqlite3_column_text((sqlite3_stmt*) __pEnum, i);
463                         memcpy(pData.get(), pTextData, size);
464                         pDbColumn->size = size;
465                         pDbColumn->pData = move(pData);
466                         break;
467                 }
468                 case SQLITE_BLOB:
469                 {
470                         int size = sqlite3_column_bytes((sqlite3_stmt*) __pEnum, i);
471                         unique_ptr<char[]> pData(new (std::nothrow) char[size + 1]);
472                         SysTryReturnResult(NID_IO, pData != null, E_OUT_OF_MEMORY, "The memory is insufficient.");
473                         memset(pData.get(), 0, size + 1);
474                         char* pBlobData = (char*) sqlite3_column_blob((sqlite3_stmt*) __pEnum, i);
475                         memcpy(pData.get(), pBlobData, size);
476                         pDbColumn->size = size;
477                         pDbColumn->pData = move(pData);
478                         break;
479                 }
480                 case SQLITE_NULL:
481                 {
482                         int size = sqlite3_column_bytes((sqlite3_stmt*) __pEnum, i);
483                         pDbColumn->size = size;
484                         break;
485                 }
486                 default:
487                 {
488                         SysTryReturnResult(NID_IO, false, E_DATABASE, "The column type is invalid.");
489                         break;
490                 }
491                 }
492
493                 dbRowSize += pDbColumn->size;
494                 r = dbRow.dbValuesList.Add(*pDbColumn.release());
495                 SysTryCatch(NID_IO, !IsFailed(r), , r, "[%s] Propagated.", GetErrorMessage(r));
496         }
497
498         __pDbEnumeratorCache->__currentUsedMemory += dbRowSize;
499
500         if (__pDbEnumeratorCache->__currentUsedMemory > _MAX_DB_CACHE_SIZE)
501         {
502                  // In this case remove old rows in LIFO manner till there is enough space for the current row.
503                 for (int i = __pDbEnumeratorCache->__dbRowList.GetCount() - 1; i >= 0; i--)
504                 {
505                         _DbRow* pTmpDbRow = dynamic_cast< _DbRow* >(__pDbEnumeratorCache->__dbRowList.GetAt(i));
506                         SysTryCatch(NID_IO, pTmpDbRow != null, r = GetLastResult(), GetLastResult(), "[%s] Propagated.", GetErrorMessage(GetLastResult()));
507                         if (pTmpDbRow->hasData == true)
508                         {
509                                 pTmpDbRow->dbValuesList.RemoveAll(true);
510                                 pTmpDbRow->hasData = false;
511                                 __pDbEnumeratorCache->__currentUsedMemory -= pTmpDbRow->dataSize;
512                                 pTmpDbRow->dataSize = 0;
513
514                                 if (__pDbEnumeratorCache->__currentUsedMemory <= _MAX_DB_CACHE_SIZE)
515                                 {
516                                         break; // found enough space.
517                                 }
518                         }
519                 }
520         }
521
522         dbRow.hasData = true;
523         dbRow.dataSize = dbRowSize;
524         __currentRowIndex = rowIndex;
525
526         // set current cursor
527         __pDbEnumeratorCache->__pCurrentDbRow = &dbRow;
528
529
530         return E_SUCCESS;
531
532 CATCH:
533         dbRow.dbValuesList.RemoveAll(true);
534         dbRow.hasData = false;
535
536         return r;
537 }
538
539 result
540 _DbEnumeratorImpl::MoveNext(void)
541 {
542         SysTryReturnResult(NID_IO, __pEnum != null, E_INVALID_STATE,
543                         "The Object is not constructed or the database is already been closed.");
544
545         _DbRow* pDbRow = null;
546         result r = E_SUCCESS;
547
548         if (__pDbEnumeratorCache == null) // called for the first time
549         {
550                 __pDbEnumeratorCache = new (std::nothrow) _DbEnumeratorCache; // allocate only once
551                 SysTryReturnResult(NID_IO, __pDbEnumeratorCache != null, E_OUT_OF_MEMORY,
552                                         "The memory is insufficient.");
553
554                 __columnCount = sqlite3_column_count((sqlite3_stmt*) __pEnum);
555
556                 SysLog(NID_IO, "__columnCount: %d", __columnCount);
557
558                 return this->CacheRow(true);
559         }
560         else
561         {
562                 SysLog(NID_IO, "current used memory:%d", __pDbEnumeratorCache->__currentUsedMemory);
563                 if ((__currentRowIndex + 1 <= __pDbEnumeratorCache->__dbRowList.GetCount() - 1))
564                 {
565                         pDbRow = dynamic_cast <_DbRow*>(__pDbEnumeratorCache->__dbRowList.GetAt(__currentRowIndex + 1));
566                         SysTryReturnResult(NID_IO, pDbRow != null, E_SYSTEM, "The method cannot proceed due to a severe system error.");
567
568                         if (pDbRow->hasData == true)
569                         {
570                                 ++__currentRowIndex;
571                                 __pDbEnumeratorCache->__pCurrentDbRow = pDbRow;
572                         }
573                         else
574                         {
575                                 return CacheRow(*pDbRow, __currentRowIndex + 1);
576                         }
577                 }
578                 else
579                 {
580                         return this->CacheRow();
581                 }
582         }
583
584         return r;
585 }
586
587 result
588 _DbEnumeratorImpl::MovePrevious(void)
589 {
590         result r = E_SUCCESS;
591
592         SysTryReturnResult(NID_IO, __pEnum != null, E_INVALID_STATE,
593                                 "The Object is not constructed or the database is already been closed.");
594         SysTryReturn(NID_IO, __pDbEnumeratorCache != null, E_INVALID_STATE, E_INVALID_STATE,
595                                 "[E_INVALID_STATE] The method has tried to fetch the column data of a result set that is not activated.");
596         SysTryReturnResult(NID_IO,  __currentRowIndex > 0, E_OUT_OF_RANGE,
597                                 "The Method has reached out of the result set.");
598
599         // since no restriction on window size, this case should work all the times.
600         __pDbEnumeratorCache->__pCurrentDbRow = dynamic_cast< _DbRow* >(__pDbEnumeratorCache->__dbRowList.GetAt(__currentRowIndex - 1));
601
602         if (__pDbEnumeratorCache->__pCurrentDbRow)
603         {
604                 if (__pDbEnumeratorCache->__pCurrentDbRow->hasData == true)
605                 {
606                         __currentRowIndex--;
607                 }
608                 else
609                 {
610                         return CacheRow(*(__pDbEnumeratorCache->__pCurrentDbRow), __currentRowIndex - 1);
611                 }
612         }
613
614         return r;
615 }
616
617 result
618 _DbEnumeratorImpl::MoveFirst(void)
619 {
620         SysTryReturnResult(NID_IO, __pEnum != null, E_INVALID_STATE,
621                                 "The Object is not constructed or the database is already been closed.");
622
623         if (__pDbEnumeratorCache == null) // if called for the first time
624         {
625                 return this->MoveNext();
626         }
627         else
628         {
629                 if (__currentRowIndex == 0)
630                 {
631                         return E_SUCCESS; // __pCurrentDbRow cursor is pointing to first row
632                 }
633                 else
634                 {
635                         __pDbEnumeratorCache->__pCurrentDbRow = dynamic_cast< _DbRow* >(__pDbEnumeratorCache->__dbRowList.GetAt(0));
636                         if (__pDbEnumeratorCache->__pCurrentDbRow)
637                         {
638                                 if (__pDbEnumeratorCache->__pCurrentDbRow->hasData == true)
639                                 {
640                                         __currentRowIndex = 0;
641                                 }
642                                 else
643                                 {
644                                         return CacheRow(*(__pDbEnumeratorCache->__pCurrentDbRow), 0);
645                                 }
646                         }
647                         else // this should not happen!!
648                         {
649                                 // reset and do MoveNext()
650                                 delete __pDbEnumeratorCache;
651                                 __pDbEnumeratorCache = null;
652                                 __currentRowIndex = -1;
653                                 __rowCount = 0;
654
655                                 result r = this->Reset(); // to call sqlite3_reset()
656                                 SysTryReturnResult(NID_IO, r == E_SUCCESS, r, "Propagated.");
657
658                                 return this->MoveNext();
659                         }
660                 }
661         }
662
663         return E_SUCCESS;
664 }
665
666 result
667 _DbEnumeratorImpl::MoveLast(void)
668 {
669         result r = E_SUCCESS;
670         _DbRow* pDbRow = null;
671
672         SysTryReturnResult(NID_IO, __pEnum != null, E_INVALID_STATE,
673                                 "The Object is not constructed or the database is already been closed.");
674
675         if (__pDbEnumeratorCache == null) // if called for the first time
676         {
677                 // make a fisrt move
678                 r = this->MoveNext();
679                 SysTryReturnResult(NID_IO, r == E_SUCCESS, r, "Propagated.");
680
681                 // cache all the rows
682                 while (true)
683                 {
684                         r = this->CacheRow();
685                         if (r == E_OUT_OF_RANGE)
686                         {
687                                 r = E_SUCCESS;
688                                 break;
689                         }
690                 }
691         }
692         else
693         {
694                 if (__rowCount > 0 && __currentRowIndex == (__rowCount - 1))
695                 {
696                         return E_SUCCESS; // already @last row.
697                 }
698
699                 // move cursor from __currentRowIndex + 1 to the end of the row list.
700                 for (int i = __currentRowIndex + 1; i < __pDbEnumeratorCache->__dbRowList.GetCount(); i++)
701                 {
702                         // find the missing row index
703                         pDbRow = dynamic_cast< _DbRow* >(__pDbEnumeratorCache->__dbRowList.GetAt(i));
704                         if (pDbRow != null)
705                         {
706                                 if (pDbRow->hasData == true)
707                                 {
708                                         __pDbEnumeratorCache->__pCurrentDbRow = pDbRow;
709                                         __currentRowIndex = i;
710                                 }
711                                 else
712                                 {
713                                         r = this->CacheRow(*pDbRow, i);
714                                         SysTryReturn(NID_IO, !(IsFailed(r)), r, r, "[%s] Propagated.", GetErrorMessage(r));
715                                 }
716                         }
717                         else
718                         {
719                                 break;
720                         }
721                 }
722
723                 if (__rowCount > 0 && __currentRowIndex == (__rowCount - 1))
724                 {
725                         return E_SUCCESS; // __dbRowList contains all the rows and __currentRowIndex is @last row.
726                 }
727                 else
728                 {
729                         // cache remaining rows
730                         while (true)
731                         {
732                                 r = this->CacheRow();
733                                 if (r == E_OUT_OF_RANGE)
734                                 {
735                                         r = E_SUCCESS;
736                                         break;
737                                 }
738                         }
739                 }
740         }
741
742         return r;
743 }
744
745 result
746 _DbEnumeratorImpl::Reset(void)
747 {
748         SysTryReturnResult(NID_IO, __pEnum != null, E_INVALID_STATE,
749                         "The Object is not constructed or the database is already been closed.");
750
751         int ret = 0;
752         result r = E_SUCCESS;
753
754         if (__pDbEnumeratorCache != null)
755         {
756                 // by resetting row offset and current row, can re-use the cache for later purpose.
757                 __pDbEnumeratorCache->__pCurrentDbRow = null;
758                 __currentRowIndex = -1;
759         }
760         else
761         {
762                 ret = sqlite3_reset((sqlite3_stmt*) __pEnum);
763                 if (ret != SQLITE_OK)
764                 {
765                         if (!_AppInfo::IsOspCompat())
766                         {
767                                 r = __ConvertNativeSqliteErrorToDetailResult(ret);
768                                 switch (ret)
769                                 {
770                                 case E_INVALID_ARG:
771                                 case E_ILLEGAL_ACCESS:
772                                 case E_IO:
773                                 case E_INVALID_FORMAT:
774                                 case E_STORAGE_FULL:
775                                 case E_INVALID_OPERATION:
776                                 case E_UNKNOWN:
777                                         r = E_SYSTEM;
778                                         break;
779                                 }
780                         }
781                         else
782                         {
783                                 r = __ConvertNativeSqliteErrorToResult(ret);
784                         }
785
786                         SysLog(NID_IO, "[%s] Failed to reset SQL statement. (%d, %s).", GetErrorMessage(r),
787                                         ret, sqlite3_errmsg(static_cast< sqlite3* >(__pDatabase)));
788                 }
789         }
790
791         return r;
792 }
793
794 result
795 _DbEnumeratorImpl::GetIntAt(int columnIndex, int& value) const
796 {
797         SysTryReturnResult(NID_IO, __pEnum != null, E_INVALID_STATE,
798                                 "The Object is not constructed or the database is already been closed.");
799         SysTryReturnResult(NID_IO, columnIndex >= 0 && columnIndex < __columnCount, E_INVALID_ARG,
800                                 "Given column index is out of range.");
801         SysTryReturnResult(NID_IO, __pDbEnumeratorCache != null, E_INVALID_STATE,
802                                 "The method has tried to fetch the column data of a result set that is not activated.");
803         SysTryReturnResult(NID_IO, __pDbEnumeratorCache->__pCurrentDbRow != null, E_SYSTEM,
804                                 "Result row is not activated.");
805
806         _DbColumn* pDbColumn = dynamic_cast < _DbColumn* >(__pDbEnumeratorCache->__pCurrentDbRow->dbValuesList.GetAt(columnIndex));
807         SysTryReturnResult(NID_IO, pDbColumn != null, E_SYSTEM, "The specified column at index %d is not found from the result set.", columnIndex);
808
809         SysTryReturnResult(NID_IO, pDbColumn->type == SQLITE_INTEGER, E_TYPE_MISMATCH,
810                         "Trying to access column of different type.");
811
812         SysTryReturnResult(NID_IO, pDbColumn->pData != null, E_SYSTEM,  "Data for specified column does not exist.");
813
814         value = *((int *)pDbColumn->pData.get());
815
816         return E_SUCCESS;
817 }
818
819 result
820 _DbEnumeratorImpl::GetInt64At(int columnIndex, long long& value) const
821 {
822         SysTryReturnResult(NID_IO, __pEnum != null, E_INVALID_STATE,
823                                 "The Object is not constructed or the database is already been closed.");
824         SysTryReturnResult(NID_IO, columnIndex >= 0 && columnIndex < __columnCount, E_INVALID_ARG,
825                                 "Given column index is out of range.");
826         SysTryReturnResult(NID_IO, __pDbEnumeratorCache != null, E_INVALID_STATE,
827                                 "The method has tried to fetch the column data of a result set that is not activated.");
828         SysTryReturnResult(NID_IO, __pDbEnumeratorCache->__pCurrentDbRow != null, E_SYSTEM,
829                                 "Result row is not activated.");
830
831         _DbColumn* pDbColumn = dynamic_cast < _DbColumn* >(__pDbEnumeratorCache->__pCurrentDbRow->dbValuesList.GetAt(columnIndex));
832         SysTryReturnResult(NID_IO, pDbColumn != null, E_SYSTEM, "The specified column at index %d is not found from the result set.", columnIndex);
833
834         SysTryReturnResult(NID_IO, pDbColumn->type == SQLITE_INTEGER, E_TYPE_MISMATCH,
835                         "Trying to access column of different type.");
836         SysTryReturnResult(NID_IO, pDbColumn->pData != null, E_SYSTEM,  "Data for specified column does not exist.");
837
838         value = *((long long *)pDbColumn->pData.get());
839
840         return E_SUCCESS;
841 }
842
843 result
844 _DbEnumeratorImpl::GetDoubleAt(int columnIndex, double& value) const
845 {
846         SysTryReturnResult(NID_IO, __pEnum != null, E_INVALID_STATE,
847                                 "The Object is not constructed or the database is already been closed.");
848         SysTryReturnResult(NID_IO, columnIndex >= 0 && columnIndex < __columnCount, E_INVALID_ARG,
849                                 "Given column index is out of range.");
850         SysTryReturnResult(NID_IO, __pDbEnumeratorCache != null, E_INVALID_STATE,
851                                 "The method has tried to fetch the column data of a result set that is not activated.");
852         SysTryReturnResult(NID_IO, __pDbEnumeratorCache->__pCurrentDbRow != null, E_SYSTEM,
853                                 "Result row is not activated.");
854
855         _DbColumn* pDbColumn = dynamic_cast < _DbColumn* >(__pDbEnumeratorCache->__pCurrentDbRow->dbValuesList.GetAt(columnIndex));
856         SysTryReturnResult(NID_IO, pDbColumn != null, E_SYSTEM, "The specified column at index %d is not found from the result set.", columnIndex);
857         SysTryReturnResult(NID_IO, pDbColumn->type == SQLITE_FLOAT, E_TYPE_MISMATCH, "Trying to access column of different type.");
858         SysTryReturnResult(NID_IO, pDbColumn->pData != null, E_SYSTEM,  "Data for specified column does not exist.");
859
860         value = *((double *)pDbColumn->pData.get());
861
862         return E_SUCCESS;
863 }
864
865 result
866 _DbEnumeratorImpl::GetStringAt(int columnIndex, String& value) const
867 {
868         SysTryReturnResult(NID_IO, __pEnum != null, E_INVALID_STATE,
869                                 "The Object is not constructed or the database is already been closed.");
870         SysTryReturnResult(NID_IO, columnIndex >= 0 && columnIndex < __columnCount, E_INVALID_ARG,
871                                 "Given column index is out of range.");
872         SysTryReturnResult(NID_IO, __pDbEnumeratorCache != null, E_INVALID_STATE,
873                                 "The method has tried to fetch the column data of a result set that is not activated.");
874         SysTryReturnResult(NID_IO, __pDbEnumeratorCache->__pCurrentDbRow != null, E_SYSTEM,
875                                 "Result row is not activated.");
876
877         _DbColumn* pDbColumn = dynamic_cast < _DbColumn* >(__pDbEnumeratorCache->__pCurrentDbRow->dbValuesList.GetAt(columnIndex));
878         SysTryReturnResult(NID_IO, pDbColumn != null, E_SYSTEM, "The specified column at index %d is not found from the result set.", columnIndex);
879         SysTryReturnResult(NID_IO, pDbColumn->type == SQLITE_TEXT, E_TYPE_MISMATCH, "Trying to access column of different type.");
880         SysTryReturnResult(NID_IO, pDbColumn->pData != null, E_SYSTEM,  "Data for specified column does not exist.");
881
882         result r = StringUtil::Utf8ToString(const_cast< char* >(pDbColumn->pData.get()), value);
883         SysTryReturn(NID_IO, r == E_SUCCESS, r, r, "[%s] Propagating to caller...", GetErrorMessage(r));
884
885         return E_SUCCESS;
886 }
887
888 result
889 _DbEnumeratorImpl::GetBlobAt(int columnIndex, ByteBuffer& value) const
890 {
891         SysTryReturnResult(NID_IO, __pEnum != null, E_INVALID_STATE,
892                                 "The Object is not constructed or the database is already been closed.");
893         SysTryReturnResult(NID_IO, columnIndex >= 0 && columnIndex < __columnCount, E_INVALID_ARG,
894                                 "Given column index is out of range.");
895         SysTryReturnResult(NID_IO, __pDbEnumeratorCache != null, E_INVALID_STATE,
896                                 "The method has tried to fetch the column data of a result set that is not activated.");
897         SysTryReturnResult(NID_IO, __pDbEnumeratorCache->__pCurrentDbRow != null, E_SYSTEM,
898                                 "Result row is not activated.");
899
900         _DbColumn* pDbColumn = dynamic_cast < _DbColumn* >(__pDbEnumeratorCache->__pCurrentDbRow->dbValuesList.GetAt(columnIndex));
901         SysTryReturnResult(NID_IO, pDbColumn != null, E_SYSTEM, "The specified column at index %d is not found from the result set.", columnIndex);
902         SysTryReturnResult(NID_IO, pDbColumn->type == SQLITE_BLOB, E_TYPE_MISMATCH, "Trying to access column of different type.");
903
904         int blobLen = pDbColumn->size;
905         SysTryReturnResult(NID_IO, pDbColumn->pData != null, E_SYSTEM,  "Data for specified column does not exist.");
906
907         const byte* pBlob = reinterpret_cast< const byte* >(pDbColumn->pData.get());
908         result r = value.SetArray(pBlob, 0, blobLen);
909         SysTryReturn(NID_IO, r == E_SUCCESS, r, r, "[%s] Propagating to caller...", GetErrorMessage(r));
910
911         return E_SUCCESS;
912 }
913
914 result
915 _DbEnumeratorImpl::GetBlobAt(int columnIndex, void* buffer, int size) const
916 {
917         SysTryReturnResult(NID_IO, __pEnum != null, E_INVALID_STATE,
918                                 "The Object is not constructed or the database is already been closed.");
919         SysTryReturnResult(NID_IO, columnIndex >= 0 && columnIndex < __columnCount, E_INVALID_ARG,
920                                 "Given column index is out of range.");
921         SysTryReturnResult(NID_IO, buffer != null, E_INVALID_ARG, "Null pointer was passed.");
922         SysTryReturnResult(NID_IO, size > 0, E_INVALID_ARG, "Invalid size was passed.");
923         SysTryReturnResult(NID_IO, __pDbEnumeratorCache != null, E_INVALID_STATE,
924                                 "The method has tried to fetch the column data of a result set that is not activated.");
925         SysTryReturnResult(NID_IO, __pDbEnumeratorCache->__pCurrentDbRow != null, E_SYSTEM,
926                                 "Result row is not activated.");
927
928         _DbColumn* pDbColumn = dynamic_cast < _DbColumn* >(__pDbEnumeratorCache->__pCurrentDbRow->dbValuesList.GetAt(columnIndex));
929         SysTryReturnResult(NID_IO, pDbColumn != null, E_SYSTEM, "The specified column at index %d is not found from the result set.", columnIndex);
930         SysTryReturnResult(NID_IO, pDbColumn->type == SQLITE_BLOB, E_TYPE_MISMATCH, "Trying to access column of different type.");
931
932         int blobLen = pDbColumn->size;
933         SysTryReturnResult(NID_IO, pDbColumn->pData != null, E_SYSTEM,  "Data for specified column does not exist.");
934
935         const byte* pBlob = reinterpret_cast< const byte* >(pDbColumn->pData.get());
936         memcpy(buffer, pBlob, (blobLen < size) ? blobLen : size);
937
938         if (size < blobLen)
939         {
940                 return E_OVERFLOW;
941         }
942
943         return E_SUCCESS;
944 }
945
946 result
947 _DbEnumeratorImpl::GetDateTimeAt(int columnIndex, DateTime& value) const
948 {
949         SysTryReturnResult(NID_IO, __pEnum != null, E_INVALID_STATE,
950                                 "The Object is not constructed or the database is already been closed.");
951         SysTryReturnResult(NID_IO, columnIndex >= 0 && columnIndex < __columnCount, E_INVALID_ARG,
952                                 "Given column index is out of range.");
953         SysTryReturnResult(NID_IO, __pDbEnumeratorCache != null, E_INVALID_STATE,
954                                 "The method has tried to fetch the column data of a result set that is not activated.");
955         SysTryReturnResult(NID_IO, __pDbEnumeratorCache->__pCurrentDbRow != null, E_SYSTEM,
956                                 "Result row is not activated.");
957
958         _DbColumn* pDbColumn = dynamic_cast < _DbColumn* >(__pDbEnumeratorCache->__pCurrentDbRow->dbValuesList.GetAt(columnIndex));
959         SysTryReturnResult(NID_IO, pDbColumn != null, E_SYSTEM, "The specified column at index %d is not found from the result set.", columnIndex);
960         SysTryReturnResult(NID_IO, pDbColumn->type == SQLITE_TEXT, E_TYPE_MISMATCH, "Trying to access column of different type.");
961         SysTryReturnResult(NID_IO, pDbColumn->pData != null, E_SYSTEM,  "Data for specified column does not exist.");
962
963         const char* pStr = const_cast< char* >(pDbColumn->pData.get());
964
965         result r = DateTime::Parse(pStr, value);
966         SysTryReturn(NID_IO, r == E_SUCCESS, r, r, "[%s] Propagating to caller...", GetErrorMessage(r));
967
968         return E_SUCCESS;
969 }
970
971 int
972 _DbEnumeratorImpl::GetColumnCount(void) const
973 {
974         SysTryReturn(NID_IO, __pEnum != null, -1, E_INVALID_STATE,
975                                 "[E_INVALID_STATE] This instance has not been properly constructed yet or has already been finalized.");
976         SysTryReturn(NID_IO, __pDbEnumeratorCache != null, -1, E_INVALID_STATE,
977                                 "[E_INVALID_STATE] The method has tried to fetch the column data of a result set that is not activated.");
978
979         return __columnCount;
980 }
981
982 DbColumnType
983 _DbEnumeratorImpl::GetColumnType(int columnIndex) const
984 {
985         DbColumnType type = DB_COLUMNTYPE_UNDEFINED;
986
987         SysTryReturn(NID_IO, __pEnum != null, DB_COLUMNTYPE_UNDEFINED, E_INVALID_STATE,
988                                 "[E_INVALID_STATE] This instance has not been properly constructed yet or has already been finalized.");
989
990         SysTryReturn(NID_IO, columnIndex >= 0 && columnIndex < __columnCount, DB_COLUMNTYPE_UNDEFINED, E_INVALID_ARG,
991                                 "[E_INVALID_ARG] Given column index is out of range.");
992
993         SysTryReturn(NID_IO, __pDbEnumeratorCache != null, DB_COLUMNTYPE_UNDEFINED, E_INVALID_STATE,
994                                 "[E_INVALID_STATE] The method has tried to fetch the column data of a result set that is not activated.");
995
996         if (__pDbEnumeratorCache->__pCurrentDbRow)
997         {
998                 _DbColumn* pDbColumn = dynamic_cast < _DbColumn* >(__pDbEnumeratorCache->__pCurrentDbRow->dbValuesList.GetAt(columnIndex));
999                 if (!pDbColumn)
1000                 {
1001                         SetLastResult(E_INVALID_STATE);
1002                         return DB_COLUMNTYPE_UNDEFINED;
1003                 }
1004                 switch (pDbColumn->type)
1005                 {
1006                 case SQLITE_INTEGER:
1007                         type = DB_COLUMNTYPE_INT;
1008                         break;
1009
1010                 case SQLITE_FLOAT:
1011                         type = DB_COLUMNTYPE_DOUBLE;
1012                         break;
1013
1014                 case SQLITE_TEXT:
1015                         type = DB_COLUMNTYPE_TEXT;
1016                         break;
1017
1018                 case SQLITE_BLOB:
1019                         type = DB_COLUMNTYPE_BLOB;
1020                         break;
1021
1022                 case SQLITE_NULL:
1023                         type = DB_COLUMNTYPE_NULL;
1024                         break;
1025
1026                 default:
1027                         SetLastResult(E_INVALID_STATE);
1028                         break;
1029                 }
1030         }
1031
1032         return type;
1033 }
1034
1035 String
1036 _DbEnumeratorImpl::GetColumnName(int columnIndex) const
1037 {
1038         SysTryReturn(NID_IO, __pEnum != null, null, E_INVALID_STATE,
1039                                 "[E_INVALID_STATE] This instance has not been properly constructed yet or has already been finalized.");
1040
1041         SysTryReturn(NID_IO, columnIndex >= 0 && columnIndex < __columnCount, null, E_INVALID_ARG,
1042                                 "[E_INVALID_ARG] Given column index is out of range.");
1043
1044         SysTryReturn(NID_IO, __pDbEnumeratorCache != null, null, E_INVALID_STATE,
1045                                 "[E_INVALID_STATE] The method has tried to fetch the column data of a result set that is not activated.");
1046
1047         String* pString = dynamic_cast <String *> (__pDbEnumeratorCache->__dbColumnNameList.GetAt(columnIndex));
1048
1049         if (!pString)
1050         {
1051                 SetLastResult(E_INVALID_STATE);
1052                 return String("");
1053         }
1054
1055         return String(pString->GetPointer());
1056 }
1057
1058 int
1059 _DbEnumeratorImpl::GetColumnSize(int columnIndex) const
1060 {
1061         int bytes = 0;
1062
1063         SysTryReturn(NID_IO, __pEnum != null, 0, E_INVALID_STATE,
1064                                 "[E_INVALID_STATE] This instance has not been properly constructed yet or has already been finalized.");
1065
1066         SysTryReturn(NID_IO, columnIndex >= 0 && columnIndex < __columnCount, 0, E_INVALID_ARG,
1067                                 "[E_INVALID_ARG] Given column index is out of range.");
1068
1069         SysTryReturn(NID_IO, __pDbEnumeratorCache != null, 0, E_INVALID_STATE,
1070                                 "[E_INVALID_STATE] The method has tried to fetch the column data of a result set that is not activated.");
1071
1072         if (__pDbEnumeratorCache->__pCurrentDbRow)
1073         {
1074                 _DbColumn* pDbColumn = dynamic_cast < _DbColumn* >(__pDbEnumeratorCache->__pCurrentDbRow->dbValuesList.GetAt(columnIndex));
1075                 if (!pDbColumn)
1076                 {
1077                         SetLastResult(E_INVALID_STATE);
1078                         return 0;
1079                 }
1080                 int columnType = pDbColumn->type;
1081
1082                 switch (columnType)
1083                 {
1084                 case SQLITE_INTEGER:
1085                         if (_AppInfo::IsOspCompat())
1086                         {
1087                                 bytes = sizeof(int); // for 2.0 compatibility
1088                         }
1089                         else
1090                         {
1091                                 bytes = sizeof(long long);
1092                         }
1093                         break;
1094
1095                 case SQLITE_FLOAT:
1096                         bytes = sizeof(double);
1097                         break;
1098
1099                 case SQLITE_TEXT:
1100                 // fall thru
1101                 case SQLITE_BLOB:
1102                         bytes = pDbColumn->size;
1103                         break;
1104
1105                 default:
1106                         SetLastResult(E_INVALID_STATE);
1107                         break;
1108                 }
1109         }
1110
1111         return bytes;
1112 }
1113
1114 _DbEnumeratorImpl*
1115 _DbEnumeratorImpl::GetInstance(DbEnumerator& dbEnumerator)
1116 {
1117         return dbEnumerator.__pDbEnumeratorImpl;
1118 }
1119
1120 const _DbEnumeratorImpl*
1121 _DbEnumeratorImpl::GetInstance(const DbEnumerator& dbEnumerator)
1122 {
1123         return dbEnumerator.__pDbEnumeratorImpl;
1124 }
1125
1126 DbEnumerator*
1127 _DbEnumeratorImpl::CreateDbEnumeratorInstanceN(void)
1128 {
1129         unique_ptr<DbEnumerator> pDbEnumerator(new (std::nothrow) DbEnumerator());
1130         SysTryReturn(NID_IO, pDbEnumerator != null, null, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] The memory is insufficient.");
1131         return pDbEnumerator.release();
1132 }
1133
1134 }} // Tizen::Io
1135