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