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