4eca1bc9835cba9e75b319fcc20572ed5bfe609f
[iotivity.git] / resource / csdk / resource-directory / src / internal / rd_database.c
1 //******************************************************************
2 //
3 // Copyright 2016 Samsung Electronics All Rights Reserved.
4 //
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
6 //
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License a
10 //
11 //      http://www.apache.org/licenses/LICENSE-2.0
12 //
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
18 //
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
20
21 #include <assert.h>
22 #include <stdlib.h>
23 #include <string.h>
24
25 #include "sqlite3.h"
26 #include "logger.h"
27 #include "ocpayload.h"
28 #include "octypes.h"
29 #include "oic_malloc.h"
30 #include "oic_string.h"
31 #include "ocstackinternal.h"
32
33 #ifdef RD_SERVER
34
35 #define TAG "OIC_RD_DATABASE"
36
37 static sqlite3 *gRDDB = NULL;
38
39 #define CHECK_DATABASE_INIT \
40     if (!gRDDB) \
41     { \
42         OIC_LOG(ERROR, TAG, "Database is not initialized."); \
43         return OC_STACK_ERROR; \
44     }
45
46 #define VERIFY_SQLITE(arg) \
47     if (SQLITE_OK != (res = (arg))) \
48     { \
49         OIC_LOG_V(ERROR, TAG, "Error in " #arg ", Error Message: %s",  sqlite3_errmsg(gRDDB)); \
50         goto exit; \
51     }
52
53 #define STR(a) #a
54 #define XSTR(a) STR(a)
55
56 #define RD_TABLE \
57     "create table RD_DEVICE_LIST(ID INTEGER PRIMARY KEY AUTOINCREMENT, " \
58     XSTR(OC_RSRVD_DEVICE_ID) " UNIQUE NOT NULL, " \
59     XSTR(OC_RSRVD_TTL) " NOT NULL);"
60
61 #define RD_LL_TABLE  \
62     "create table RD_DEVICE_LINK_LIST("XSTR(OC_RSRVD_INS)" INTEGER PRIMARY KEY AUTOINCREMENT, " \
63     XSTR(OC_RSRVD_HREF) "," \
64     XSTR(OC_RSRVD_REL) ","  \
65     XSTR(OC_RSRVD_URI) "," \
66     XSTR(OC_RSRVD_BITMAP) "," \
67     "DEVICE_ID INT NOT NULL, " \
68     "FOREIGN KEY(DEVICE_ID) REFERENCES RD_DEVICE_LIST(ID) ON DELETE CASCADE);"
69
70 #define RD_RT_TABLE \
71     "create table RD_LINK_RT(" XSTR(OC_RSRVD_RESOURCE_TYPE) " NOT NULL, " \
72     "LINK_ID INT NOT NULL, " \
73     "FOREIGN KEY("XSTR(LINK_ID)") REFERENCES RD_DEVICE_LINK_LIST("XSTR(OC_RSRVD_INS)") " \
74     "ON DELETE CASCADE);"
75
76 #define RD_IF_TABLE \
77     "create table RD_LINK_IF(" XSTR(OC_RSRVD_INTERFACE) " NOT NULL, " \
78     "LINK_ID INT NOT NULL, "\
79     "FOREIGN KEY("XSTR(LINK_ID)") REFERENCES RD_DEVICE_LINK_LIST("XSTR(OC_RSRVD_INS)") " \
80     "ON DELETE CASCADE);"
81
82 #define RD_EP_TABLE \
83     "create table RD_LINK_EP(" XSTR(OC_RSRVD_ENDPOINT) " NOT NULL, " \
84     XSTR(OC_RSRVD_PRIORITY) " INT NOT NULL, " \
85     "LINK_ID INT NOT NULL, "\
86     "FOREIGN KEY("XSTR(LINK_ID)") REFERENCES RD_DEVICE_LINK_LIST("XSTR(OC_RSRVD_INS)") " \
87     "ON DELETE CASCADE);"
88
89 static void errorCallback(void *arg, int errCode, const char *errMsg)
90 {
91     OC_UNUSED(arg);
92     OC_UNUSED(errCode);
93     OC_UNUSED(errMsg);
94     OIC_LOG_V(ERROR, TAG, "SQLLite Error: %s : %d", errMsg, errCode);
95 }
96
97 static bool stringArgumentWithinBounds(const char* argument)
98 {
99     return ((NULL == argument) || (strlen(argument) <= INT_MAX));
100 }
101
102 static bool stringArgumentsWithinBounds(const char** arguments, size_t count)
103 {
104     for (size_t index = 0; index < count; index++)
105     {
106         if (!stringArgumentWithinBounds(arguments[index]))
107         {
108             return false;
109         }
110     }
111
112     return true;
113 }
114
115 static int storeResourceTypes(char **resourceTypes, size_t size, sqlite3_int64 rowid)
116 {
117     int res = 1;
118     sqlite3_stmt *stmt = NULL;
119     if (!stringArgumentsWithinBounds(resourceTypes, size))
120     {
121         return res;
122     }
123
124     VERIFY_SQLITE(sqlite3_exec(gRDDB, "SAVEPOINT storeResourceTypes", NULL, NULL, NULL));
125
126     static const char deleteRT[] = "DELETE FROM RD_LINK_RT WHERE LINK_ID=@id";
127     static const char insertRT[] = "INSERT INTO RD_LINK_RT VALUES(@resourceType, @id)";
128     int deleteRTSize = (int)sizeof(deleteRT);
129     int insertRTSize = (int)sizeof(insertRT);
130
131
132     VERIFY_SQLITE(sqlite3_prepare_v2(gRDDB, deleteRT, deleteRTSize, &stmt, NULL));
133     VERIFY_SQLITE(sqlite3_bind_int64(stmt, sqlite3_bind_parameter_index(stmt, "@id"), rowid));
134     res = sqlite3_step(stmt);
135     if (SQLITE_DONE != res)
136     {
137         goto exit;
138     }
139     VERIFY_SQLITE(sqlite3_finalize(stmt));
140     stmt = NULL;
141
142     for (size_t i = 0; i < size; i++)
143     {
144         VERIFY_SQLITE(sqlite3_prepare_v2(gRDDB, insertRT, insertRTSize, &stmt, NULL));
145         if (resourceTypes[i])
146         {
147             VERIFY_SQLITE(sqlite3_bind_text(stmt, sqlite3_bind_parameter_index(stmt, "@resourceType"),
148                             resourceTypes[i], (int)strlen(resourceTypes[i]), SQLITE_STATIC));
149             VERIFY_SQLITE(sqlite3_bind_int64(stmt, sqlite3_bind_parameter_index(stmt, "@id"), rowid));
150         }
151         res = sqlite3_step(stmt);
152         if (SQLITE_DONE != res)
153         {
154             goto exit;
155         }
156         VERIFY_SQLITE(sqlite3_finalize(stmt));
157         stmt = NULL;
158     }
159
160     VERIFY_SQLITE(sqlite3_exec(gRDDB, "RELEASE storeResourceTypes", NULL, NULL, NULL));
161     res = SQLITE_OK;
162
163 exit:
164     sqlite3_finalize(stmt);
165     if (SQLITE_OK != res)
166     {
167         sqlite3_exec(gRDDB, "ROLLBACK TO storeResourceTypes", NULL, NULL, NULL);
168     }
169     return res;
170 }
171
172 static int storeInterfaces(char **interfaces, size_t size, sqlite3_int64 rowid)
173 {
174     int res = 1;
175     sqlite3_stmt *stmt = NULL;
176     if (!stringArgumentsWithinBounds(interfaces, size))
177     {
178         return res;
179     }
180
181     VERIFY_SQLITE(sqlite3_exec(gRDDB, "SAVEPOINT storeInterfaces", NULL, NULL, NULL));
182
183     static const char deleteIF[] = "DELETE FROM RD_LINK_IF WHERE LINK_ID=@id";
184     static const char insertIF[] = "INSERT INTO RD_LINK_IF VALUES(@interfaceType, @id)";
185     int deleteIFLength = (int)sizeof(deleteIF);
186     int insertIFLength = (int)sizeof(insertIF);
187
188     VERIFY_SQLITE(sqlite3_prepare_v2(gRDDB, deleteIF, deleteIFLength, &stmt, NULL));
189     VERIFY_SQLITE(sqlite3_bind_int64(stmt, sqlite3_bind_parameter_index(stmt, "@id"), rowid));
190     res = sqlite3_step(stmt);
191     if (SQLITE_DONE != res)
192     {
193         goto exit;
194     }
195     VERIFY_SQLITE(sqlite3_finalize(stmt));
196     stmt = NULL;
197
198     for (size_t i = 0; i < size; i++)
199     {
200         VERIFY_SQLITE(sqlite3_prepare_v2(gRDDB, insertIF, insertIFLength, &stmt, NULL));
201         if (interfaces[i])
202         {
203             VERIFY_SQLITE(sqlite3_bind_text(stmt, sqlite3_bind_parameter_index(stmt, "@interfaceType"),
204                             interfaces[i], (int)strlen(interfaces[i]), SQLITE_STATIC));
205             VERIFY_SQLITE(sqlite3_bind_int64(stmt, sqlite3_bind_parameter_index(stmt, "@id"), rowid));
206         }
207         res = sqlite3_step(stmt);
208         if (SQLITE_DONE != res)
209         {
210             goto exit;
211         }
212         VERIFY_SQLITE(sqlite3_finalize(stmt));
213         stmt = NULL;
214     }
215
216     VERIFY_SQLITE(sqlite3_exec(gRDDB, "RELEASE storeInterfaces", NULL, NULL, NULL));
217     res = SQLITE_OK;
218
219 exit:
220     sqlite3_finalize(stmt);
221     if (SQLITE_OK != res)
222     {
223         sqlite3_exec(gRDDB, "ROLLBACK TO storeInterfaces", NULL, NULL, NULL);
224     }
225     return res;
226 }
227
228 static int storeEndpoints(OCRepPayload **eps, size_t size, sqlite3_int64 rowid)
229 {
230     int res;
231     char *ep = NULL;
232     sqlite3_stmt *stmt = NULL;
233
234     VERIFY_SQLITE(sqlite3_exec(gRDDB, "SAVEPOINT storeEndpoints", NULL, NULL, NULL));
235     static const char deleteEp[] = "DELETE FROM RD_LINK_EP WHERE LINK_ID=@id";
236     static const char insertEp[] = "INSERT INTO RD_LINK_EP VALUES(@ep, @pri, @id)";
237     int deleteEpLength = (int)sizeof(deleteEp);
238     int insertEpLength = (int)sizeof(insertEp);
239
240
241     VERIFY_SQLITE(sqlite3_prepare_v2(gRDDB, deleteEp, deleteEpLength, &stmt, NULL));
242     VERIFY_SQLITE(sqlite3_bind_int64(stmt, sqlite3_bind_parameter_index(stmt, "@id"), rowid));
243     res = sqlite3_step(stmt);
244     if (SQLITE_DONE != res)
245     {
246         goto exit;
247     }
248     VERIFY_SQLITE(sqlite3_finalize(stmt));
249     stmt = NULL;
250
251     for (size_t i = 0; i < size; i++)
252     {
253         VERIFY_SQLITE(sqlite3_prepare_v2(gRDDB, insertEp, insertEpLength, &stmt, NULL));
254         if (OCRepPayloadGetPropString(eps[i], OC_RSRVD_ENDPOINT, &ep))
255         {
256             if (!stringArgumentWithinBounds(ep))
257             {
258                 goto exit;
259             }
260             VERIFY_SQLITE(sqlite3_bind_text(stmt, sqlite3_bind_parameter_index(stmt, "@ep"),
261                             ep, (int)strlen(ep), SQLITE_STATIC));
262         }
263         sqlite3_int64 pri;
264         if (OCRepPayloadGetPropInt(eps[i], OC_RSRVD_PRIORITY, (int64_t *) &pri))
265         {
266             VERIFY_SQLITE(sqlite3_bind_int64(stmt, sqlite3_bind_parameter_index(stmt, "@pri"), pri));
267         }
268         VERIFY_SQLITE(sqlite3_bind_int64(stmt, sqlite3_bind_parameter_index(stmt, "@id"), rowid));
269         res = sqlite3_step(stmt);
270         if (SQLITE_DONE != res)
271         {
272             goto exit;
273         }
274         VERIFY_SQLITE(sqlite3_finalize(stmt));
275         stmt = NULL;
276         OICFree(ep);
277         ep = NULL;
278     }
279
280     VERIFY_SQLITE(sqlite3_exec(gRDDB, "RELEASE storeEndpoints", NULL, NULL, NULL));
281     res = SQLITE_OK;
282
283 exit:
284     OICFree(ep);
285     sqlite3_finalize(stmt);
286     if (SQLITE_OK != res)
287     {
288         sqlite3_exec(gRDDB, "ROLLBACK TO storeInterfaces", NULL, NULL, NULL);
289     }
290     return res;
291 }
292
293 static int storeLinkPayload(OCRepPayload *rdPayload, sqlite3_int64 rowid)
294 {
295     int res = SQLITE_OK;
296
297     /*
298      * Iterate over the properties manually rather than OCRepPayloadGetPropObjectArray to avoid
299      * the clone since we want to insert the 'ins' values into the payload.
300      */
301     OCRepPayloadValue *links;
302     for (links = rdPayload->values; links; links = links->next)
303     {
304         if (0 == strcmp(links->name, OC_RSRVD_LINKS))
305         {
306             if (links->type != OCREP_PROP_ARRAY || links->arr.type != OCREP_PROP_OBJECT)
307             {
308                 links = NULL;
309             }
310             break;
311         }
312     }
313     if (links != NULL)
314     {
315         sqlite3_stmt *stmt = NULL;
316         char *uri = NULL;
317         char *anchor = NULL;
318         OCRepPayload *p = NULL;
319         char **rt = NULL;
320         size_t rtDim[MAX_REP_ARRAY_DEPTH] = {0};
321         char **itf = NULL;
322         size_t itfDim[MAX_REP_ARRAY_DEPTH] = {0};
323         OCRepPayload** eps = NULL;
324         size_t epsDim[MAX_REP_ARRAY_DEPTH] = {0};
325
326         static const char insertDeviceLLList[] = "INSERT OR IGNORE INTO RD_DEVICE_LINK_LIST (ins, href, DEVICE_ID) "
327             "VALUES((SELECT ins FROM RD_DEVICE_LINK_LIST WHERE DEVICE_ID=@id AND href=@uri),@uri,@id)";
328         static const char updateDeviceLLList[] = "UPDATE RD_DEVICE_LINK_LIST SET anchor=@anchor,bm=@bm "
329             "WHERE DEVICE_ID=@id AND href=@uri";
330         int insertDeviceLLListSize = (int)sizeof(insertDeviceLLList);
331         int updateDeviceLLListSize = (int)sizeof(updateDeviceLLList);
332
333         for (size_t i = 0; (SQLITE_OK == res) && (i < links->arr.dimensions[0]); i++)
334         {
335             VERIFY_SQLITE(sqlite3_exec(gRDDB, "SAVEPOINT storeLinkPayload", NULL, NULL, NULL));
336
337             VERIFY_SQLITE(sqlite3_prepare_v2(gRDDB, insertDeviceLLList,
338                             insertDeviceLLListSize, &stmt, NULL));
339
340             OCRepPayload *link = links->arr.objArray[i];
341             VERIFY_SQLITE(sqlite3_bind_int64(stmt, sqlite3_bind_parameter_index(stmt, "@id"), rowid));
342             if (OCRepPayloadGetPropString(link, OC_RSRVD_HREF, &uri))
343             {
344                 if (!stringArgumentWithinBounds(uri))
345                 {
346                     return res;
347                 }
348                 VERIFY_SQLITE(sqlite3_bind_text(stmt, sqlite3_bind_parameter_index(stmt, "@uri"),
349                                 uri, (int)strlen(uri), SQLITE_STATIC));
350             }
351             res = sqlite3_step(stmt);
352             if (SQLITE_DONE != res)
353             {
354                 goto exit;
355             }
356             VERIFY_SQLITE(sqlite3_finalize(stmt));
357             stmt = NULL;
358
359             VERIFY_SQLITE(sqlite3_prepare_v2(gRDDB, updateDeviceLLList,
360                             updateDeviceLLListSize, &stmt, NULL));
361             VERIFY_SQLITE(sqlite3_bind_int64(stmt, sqlite3_bind_parameter_index(stmt, "@id"), rowid));
362             if (uri)
363             {
364                 VERIFY_SQLITE(sqlite3_bind_text(stmt, sqlite3_bind_parameter_index(stmt, "@uri"),
365                                 uri, (int)strlen(uri), SQLITE_STATIC));
366             }
367             if (OCRepPayloadGetPropString(link, OC_RSRVD_URI, &anchor))
368             {
369                 if (!stringArgumentWithinBounds(anchor))
370                 {
371                     goto exit;
372                 }
373                 VERIFY_SQLITE(sqlite3_bind_text(stmt, sqlite3_bind_parameter_index(stmt, "@anchor"),
374                                 anchor, (int)strlen(anchor), SQLITE_STATIC));
375             }
376             if (OCRepPayloadGetPropObject(link, OC_RSRVD_POLICY, &p))
377             {
378                 sqlite3_int64 bm = 0;
379                 if (OCRepPayloadGetPropInt(p, OC_RSRVD_BITMAP, (int64_t *) &bm))
380                 {
381                     VERIFY_SQLITE(sqlite3_bind_int64(stmt, sqlite3_bind_parameter_index(stmt, "@bm"), bm));
382                 }
383             }
384             res = sqlite3_step(stmt);
385             if (SQLITE_DONE != res)
386             {
387                 goto exit;
388             }
389             VERIFY_SQLITE(sqlite3_finalize(stmt));
390             stmt = NULL;
391
392             static const char input[] = "SELECT ins FROM RD_DEVICE_LINK_LIST WHERE DEVICE_ID=@id AND href=@uri";
393             int inputSize = (int)sizeof(input);
394
395             VERIFY_SQLITE(sqlite3_prepare_v2(gRDDB, input, inputSize, &stmt, NULL));
396             VERIFY_SQLITE(sqlite3_bind_int64(stmt, sqlite3_bind_parameter_index(stmt, "@id"), rowid));
397             if (uri)
398             {
399                 VERIFY_SQLITE(sqlite3_bind_text(stmt, sqlite3_bind_parameter_index(stmt, "@uri"),
400                                 uri, (int)strlen(uri), SQLITE_STATIC));
401             }
402             res = sqlite3_step(stmt);
403             if (res == SQLITE_ROW || res == SQLITE_DONE)
404             {
405                 sqlite3_int64 ins = sqlite3_column_int64(stmt, 0);
406                 VERIFY_SQLITE(sqlite3_finalize(stmt));
407                 stmt = NULL;
408                 if (!OCRepPayloadSetPropInt(link, OC_RSRVD_INS, ins))
409                 {
410                     OIC_LOG_V(ERROR, TAG, "Error setting 'ins' value");
411                     return OC_STACK_ERROR;
412                 }
413                 OCRepPayloadGetStringArray(link, OC_RSRVD_RESOURCE_TYPE, &rt, rtDim);
414                 OCRepPayloadGetStringArray(link, OC_RSRVD_INTERFACE, &itf, itfDim);
415                 OCRepPayloadGetPropObjectArray(link, OC_RSRVD_ENDPOINTS, &eps, epsDim);
416                 VERIFY_SQLITE(storeResourceTypes(rt, rtDim[0], ins));
417                 VERIFY_SQLITE(storeInterfaces(itf, itfDim[0], ins));
418                 VERIFY_SQLITE(storeEndpoints(eps, epsDim[0], ins));
419             }
420             else
421             {
422                 VERIFY_SQLITE(sqlite3_finalize(stmt));
423                 stmt = NULL;
424             }
425
426             VERIFY_SQLITE(sqlite3_exec(gRDDB, "RELEASE storeLinkPayload", NULL, NULL, NULL));
427             res = SQLITE_OK;
428
429         exit:
430             if (eps)
431             {
432                 for (size_t j = 0; j < epsDim[0]; j++)
433                 {
434                     OCRepPayloadDestroy(eps[j]);
435                 }
436                 OICFree(eps);
437                 eps = NULL;
438             }
439             if (itf)
440             {
441                 for (size_t j = 0; j < itfDim[0]; j++)
442                 {
443                     OICFree(itf[j]);
444                 }
445                 OICFree(itf);
446                 itf = NULL;
447             }
448             if (rt)
449             {
450                 for (size_t j = 0; j < rtDim[0]; j++)
451                 {
452                     OICFree(rt[j]);
453                 }
454                 OICFree(rt);
455                 rt = NULL;
456             }
457             OCPayloadDestroy((OCPayload *)p);
458             p = NULL;
459             OICFree(anchor);
460             anchor = NULL;
461             OICFree(uri);
462             uri = NULL;
463             sqlite3_finalize(stmt);
464             stmt = NULL;
465             if (SQLITE_OK != res)
466             {
467                 sqlite3_exec(gRDDB, "ROLLBACK TO storeLinkPayload", NULL, NULL, NULL);
468             }
469         }
470     }
471
472     return res;
473 }
474
475 static int storeResources(OCRepPayload *payload)
476 {
477     char *deviceId = NULL;
478     sqlite3_stmt *stmt = NULL;
479     OCRepPayloadGetPropString(payload, OC_RSRVD_DEVICE_ID, &deviceId);
480     if (!stringArgumentWithinBounds(deviceId))
481     {
482         return OC_STACK_ERROR;
483     }
484
485     sqlite3_int64 ttl = 0;
486     OCRepPayloadGetPropInt(payload, OC_RSRVD_DEVICE_TTL, &ttl);
487
488     int res;
489     VERIFY_SQLITE(sqlite3_exec(gRDDB, "BEGIN TRANSACTION", NULL, NULL, NULL));
490
491     /* INSERT OR IGNORE then UPDATE to update or insert the row without triggering the cascading deletes */
492     static const char insertDeviceList[] = "INSERT OR IGNORE INTO RD_DEVICE_LIST (ID, di, ttl) "
493         "VALUES ((SELECT ID FROM RD_DEVICE_LIST WHERE di=@deviceId), @deviceId, @ttl)";
494     int insertDeviceListSize = (int)sizeof(insertDeviceList);
495     VERIFY_SQLITE(sqlite3_prepare_v2(gRDDB, insertDeviceList, insertDeviceListSize,
496                     &stmt, NULL));
497     if (deviceId)
498     {
499         VERIFY_SQLITE(sqlite3_bind_text(stmt, sqlite3_bind_parameter_index(stmt, "@deviceId"),
500                         deviceId, (int)strlen(deviceId), SQLITE_STATIC));
501     }
502     if (ttl)
503     {
504         VERIFY_SQLITE(sqlite3_bind_int64(stmt, sqlite3_bind_parameter_index(stmt, "@ttl"), ttl));
505     }
506     res = sqlite3_step(stmt);
507     if (SQLITE_DONE != res)
508     {
509         goto exit;
510     }
511     VERIFY_SQLITE(sqlite3_finalize(stmt));
512     stmt = NULL;
513
514     static const char updateDeviceList[] = "UPDATE RD_DEVICE_LIST SET ttl=@ttl WHERE di=@deviceId";
515     int updateDeviceListSize = (int)sizeof(updateDeviceList);
516     VERIFY_SQLITE(sqlite3_prepare_v2(gRDDB, updateDeviceList, updateDeviceListSize,
517                     &stmt, NULL));
518     if (deviceId)
519     {
520         VERIFY_SQLITE(sqlite3_bind_text(stmt, sqlite3_bind_parameter_index(stmt, "@deviceId"),
521                         deviceId, (int)strlen(deviceId), SQLITE_STATIC));
522     }
523     if (ttl)
524     {
525         VERIFY_SQLITE(sqlite3_bind_int64(stmt, sqlite3_bind_parameter_index(stmt, "@ttl"), ttl));
526     }
527     res = sqlite3_step(stmt);
528     if (SQLITE_DONE != res)
529     {
530         goto exit;
531     }
532     VERIFY_SQLITE(sqlite3_finalize(stmt));
533     stmt = NULL;
534
535     /* Store the rest of the payload */
536     static const char input[] = "SELECT ID FROM RD_DEVICE_LIST WHERE di=@deviceId";
537     int inputSize = (int)sizeof(input);
538
539     VERIFY_SQLITE(sqlite3_prepare_v2(gRDDB, input, inputSize, &stmt, NULL));
540     if (deviceId)
541     {
542         VERIFY_SQLITE(sqlite3_bind_text(stmt, sqlite3_bind_parameter_index(stmt, "@deviceId"),
543                         deviceId, (int)strlen(deviceId), SQLITE_STATIC));
544     }
545     res = sqlite3_step(stmt);
546     if (res == SQLITE_ROW || res == SQLITE_DONE)
547     {
548         sqlite3_int64 rowid = sqlite3_column_int64(stmt, 0);
549         VERIFY_SQLITE(sqlite3_finalize(stmt));
550         stmt = NULL;
551         VERIFY_SQLITE(storeLinkPayload(payload, rowid));
552     }
553     else
554     {
555         VERIFY_SQLITE(sqlite3_finalize(stmt));
556         stmt = NULL;
557     }
558
559     VERIFY_SQLITE(sqlite3_exec(gRDDB, "COMMIT", NULL, NULL, NULL));
560     res = SQLITE_OK;
561
562 exit:
563     sqlite3_finalize(stmt);
564     OICFree(deviceId);
565     if (SQLITE_OK != res)
566     {
567         sqlite3_exec(gRDDB, "ROLLBACK", NULL, NULL, NULL);
568     }
569     return res;
570 }
571
572 static int deleteResources(const char *deviceId, const int64_t *instanceIds, uint16_t nInstanceIds)
573 {
574     char *delResource = NULL;
575     sqlite3_stmt *stmt = NULL;
576     if (!stringArgumentWithinBounds(deviceId))
577     {
578         OIC_LOG_V(ERROR, TAG, "Query longer than %d: \n%s", INT_MAX, deviceId);
579         return OC_STACK_ERROR;
580     }
581
582     int res;
583     VERIFY_SQLITE(sqlite3_exec(gRDDB, "BEGIN TRANSACTION", NULL, NULL, NULL));
584
585     if (!instanceIds || !nInstanceIds)
586     {
587         static const char delDevice[] = "DELETE FROM RD_DEVICE_LIST WHERE di=@deviceId";
588         int delDeviceSize = (int)sizeof(delDevice);
589
590         VERIFY_SQLITE(sqlite3_prepare_v2(gRDDB, delDevice, delDeviceSize, &stmt, NULL));
591         VERIFY_SQLITE(sqlite3_bind_text(stmt, sqlite3_bind_parameter_index(stmt, "@deviceId"),
592                                         deviceId, (int)strlen(deviceId), SQLITE_STATIC));
593     }
594     else
595     {
596         static const char pre[] = "DELETE FROM RD_DEVICE_LINK_LIST "
597             "WHERE ins IN ("
598             "SELECT RD_DEVICE_LINK_LIST.ins FROM RD_DEVICE_LINK_LIST "
599             "INNER JOIN RD_DEVICE_LIST ON RD_DEVICE_LINK_LIST.DEVICE_ID=RD_DEVICE_LIST.ID "
600             "WHERE RD_DEVICE_LIST.di=@deviceId AND RD_DEVICE_LINK_LIST.ins IN (";
601         size_t inLen = nInstanceIds + (nInstanceIds - 1);
602         static const char post[] = "))";
603         size_t delResourceSize = sizeof(pre) + inLen + (sizeof(post) - 1);
604         delResource = OICCalloc(delResourceSize, 1);
605         if (!delResource)
606         {
607             res = SQLITE_NOMEM;
608             goto exit;
609         }
610         OICStrcat(delResource, delResourceSize, pre);
611         OICStrcat(delResource, delResourceSize, "?");
612         for (uint16_t i = 1; i < nInstanceIds; ++i)
613         {
614             OICStrcat(delResource, delResourceSize, ",?");
615         }
616         OICStrcat(delResource, delResourceSize, post);
617         VERIFY_SQLITE(sqlite3_prepare_v2(gRDDB, delResource, (int)delResourceSize,
618                         &stmt, NULL));
619         VERIFY_SQLITE(sqlite3_bind_text(stmt, sqlite3_bind_parameter_index(stmt, "@deviceId"),
620                         deviceId, (int)strlen(deviceId), SQLITE_STATIC));
621         assert(sqlite3_bind_parameter_index(stmt, "@deviceId") == 1);
622         for (uint16_t i = 0; i < nInstanceIds; ++i)
623         {
624             VERIFY_SQLITE(sqlite3_bind_int64(stmt, 2 + i, instanceIds[i]));
625         }
626     }
627
628     res = sqlite3_step(stmt);
629     if (SQLITE_DONE != res)
630     {
631         goto exit;
632     }
633     VERIFY_SQLITE(sqlite3_finalize(stmt));
634     stmt = NULL;
635
636     VERIFY_SQLITE(sqlite3_exec(gRDDB, "COMMIT", NULL, NULL, NULL));
637     res = SQLITE_OK;
638
639 exit:
640     OICFree(delResource);
641     sqlite3_finalize(stmt);
642     if (SQLITE_OK != res)
643     {
644         sqlite3_exec(gRDDB, "ROLLBACK", NULL, NULL, NULL);
645     }
646     return res;
647 }
648
649 OCStackResult OC_CALL OCRDDatabaseInit()
650 {
651     if (SQLITE_OK == sqlite3_config(SQLITE_CONFIG_LOG, errorCallback))
652     {
653         OIC_LOG_V(INFO, TAG, "SQLite debugging log initialized.");
654     }
655
656     sqlite3_stmt *stmt = NULL;
657     int res;
658     res = sqlite3_open_v2(OCRDDatabaseGetStorageFilename(), &gRDDB, SQLITE_OPEN_READWRITE, NULL);
659     if (SQLITE_OK != res)
660     {
661         OIC_LOG(DEBUG, TAG, "RD database file did not open, as no table exists.");
662         OIC_LOG(DEBUG, TAG, "RD creating new table.");
663         VERIFY_SQLITE(sqlite3_open_v2(OCRDDatabaseGetStorageFilename(), &gRDDB,
664                         SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL));
665
666         VERIFY_SQLITE(sqlite3_exec(gRDDB, RD_TABLE, NULL, NULL, NULL));
667         OIC_LOG(DEBUG, TAG, "RD created RD_DEVICE_LIST table.");
668
669         VERIFY_SQLITE(sqlite3_exec(gRDDB, RD_LL_TABLE, NULL, NULL, NULL));
670         OIC_LOG(DEBUG, TAG, "RD created RD_DEVICE_LINK_LIST table.");
671
672         VERIFY_SQLITE(sqlite3_exec(gRDDB, RD_RT_TABLE, NULL, NULL, NULL));
673         OIC_LOG(DEBUG, TAG, "RD created RD_LINK_RT table.");
674
675         VERIFY_SQLITE(sqlite3_exec(gRDDB, RD_IF_TABLE, NULL, NULL, NULL));
676         OIC_LOG(DEBUG, TAG, "RD created RD_LINK_IF table.");
677
678         VERIFY_SQLITE(sqlite3_exec(gRDDB, RD_EP_TABLE, NULL, NULL, NULL));
679         OIC_LOG(DEBUG, TAG, "RD created RD_LINK_EP table.");
680
681         res = SQLITE_OK;
682     }
683
684     if (SQLITE_OK == res)
685     {
686         VERIFY_SQLITE(sqlite3_prepare_v2(gRDDB, "PRAGMA foreign_keys = ON;", -1, &stmt, NULL));
687         res = sqlite3_step(stmt);
688         if (SQLITE_DONE != res)
689         {
690             goto exit;
691         }
692         VERIFY_SQLITE(sqlite3_finalize(stmt));
693         stmt = NULL;
694     }
695
696 exit:
697     sqlite3_finalize(stmt);
698     if (SQLITE_OK == res)
699     {
700         return OC_STACK_OK;
701     }
702     else
703     {
704         sqlite3_close(gRDDB);
705         gRDDB = NULL;
706         return OC_STACK_ERROR;
707     }
708 }
709
710 OCStackResult OC_CALL OCRDDatabaseClose()
711 {
712     CHECK_DATABASE_INIT;
713     int res;
714     VERIFY_SQLITE(sqlite3_close(gRDDB));
715     gRDDB = NULL;
716 exit:
717     return (SQLITE_OK == res) ? OC_STACK_OK : OC_STACK_ERROR;
718 }
719
720 OCStackResult OC_CALL OCRDDatabaseStoreResources(OCRepPayload *payload)
721 {
722     CHECK_DATABASE_INIT;
723     int res;
724     VERIFY_SQLITE(storeResources(payload));
725 exit:
726     return (SQLITE_OK == res) ? OC_STACK_OK : OC_STACK_ERROR;
727 }
728
729 OCStackResult OC_CALL OCRDDatabaseDeleteResources(const char *deviceId, const int64_t *instanceIds,
730         uint16_t nInstanceIds)
731 {
732     CHECK_DATABASE_INIT;
733     int res;
734     VERIFY_SQLITE(deleteResources(deviceId, instanceIds, nInstanceIds));
735 exit:
736     return (SQLITE_OK == res) ? OC_STACK_OK : OC_STACK_ERROR;
737 }
738
739 #endif