d502c94602fd4a0d995a114215bb0b415a324b72
[platform/upstream/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 <stdlib.h>
22 #include <string.h>
23
24 #include "sqlite3.h"
25 #include "logger.h"
26 #include "ocpayload.h"
27 #include "octypes.h"
28 #include "oic_malloc.h"
29 #include "oic_string.h"
30
31 #ifdef RD_SERVER
32
33 #define TAG "OIC_RD_DATABASE"
34 #define RD_PATH "RD.db"
35
36 static sqlite3 *gRDDB = NULL;
37
38 static const uint8_t device_index = 2;
39 static const uint8_t ttl_index = 3;
40 static const uint8_t address_index = 4;
41
42 static const uint8_t uri_index = 2;
43 static const uint8_t p_index = 5;
44 static const uint8_t mt_index = 7;
45 static const uint8_t d_index = 8;
46
47 static const uint8_t rt_value_index = 1;
48 static const uint8_t rt_link_id_index = 2;
49
50 static const uint8_t if_value_index = 1;
51 static const uint8_t if_link_id_index = 2;
52
53 #define VERIFY_SQLITE(arg) \
54     if (SQLITE_OK != (arg)) \
55     { \
56         OIC_LOG_V(ERROR, TAG, "Error in " #arg ", Error Message: %s",  sqlite3_errmsg(gRDDB)); \
57         sqlite3_exec(gRDDB, "ROLLBACK", NULL, NULL, NULL); \
58         return OC_STACK_ERROR; \
59     }
60
61 #define CHECK_DATABASE_INIT \
62     if (!gRDDB) \
63     { \
64         OIC_LOG(ERROR, TAG, "Database is not initialized."); \
65         return OC_STACK_ERROR; \
66     }
67
68 #define STR(a) #a
69 #define XSTR(a) STR(a)
70
71 #define RD_TABLE \
72     "create table RD_DEVICE_LIST(ID INTEGER PRIMARY KEY AUTOINCREMENT, " \
73     XSTR(OC_RSRVD_DEVICE_ID) " UNIQUE NOT NULL, " \
74     XSTR(OC_RSRVD_TTL) " NOT NULL, " \
75     "ADDRESS NOT NULL);"
76
77 #define RD_LL_TABLE  \
78     "create table RD_DEVICE_LINK_LIST("XSTR(OC_RSRVD_INS)" INTEGER PRIMARY KEY AUTOINCREMENT, " \
79     XSTR(OC_RSRVD_HREF)  "," \
80     XSTR(OC_RSRVD_REL)   ","  \
81     XSTR(OC_RSRVD_TITLE) "," \
82     XSTR(OC_RSRVD_BITMAP)"," \
83     XSTR(OC_RSRVD_TTL)   "," \
84     XSTR(OC_RSRVD_MEDIA_TYPE) "," \
85     "DEVICE_ID INT NOT NULL, " \
86     "FOREIGN KEY(DEVICE_ID) REFERENCES RD_DEVICE_LIST(ID) ON DELETE CASCADE );"
87
88 #define RD_RT_TABLE \
89     "create table RD_LINK_RT(" XSTR(OC_RSRVD_RESOURCE_TYPE) " NOT NULL, " \
90     "LINK_ID INT NOT NULL, "\
91     "FOREIGN KEY("XSTR(LINK_ID)") REFERENCES RD_DEVICE_LINK_LIST("XSTR(OC_RSRVD_INS)") " \
92     "ON DELETE CASCADE);"
93
94 #define RD_IF_TABLE \
95     "create table RD_LINK_IF(" XSTR(OC_RSRVD_INTERFACE) " NOT NULL, " \
96     "LINK_ID INT NOT NULL, "\
97     "FOREIGN KEY("XSTR(LINK_ID)") REFERENCES RD_DEVICE_LINK_LIST("XSTR(OC_RSRVD_INS)") " \
98     "ON DELETE CASCADE);"
99
100 static void errorCallback(void *arg, int errCode, const char *errMsg)
101 {
102     OC_UNUSED(arg);
103     OC_UNUSED(errCode);
104     OC_UNUSED(errMsg);
105     OIC_LOG_V(ERROR, TAG, "SQLLite Error: %s : %d", errMsg, errCode);
106 }
107
108 OCStackResult OCRDDatabaseInit(const char *path)
109 {
110     if (SQLITE_OK == sqlite3_config(SQLITE_CONFIG_LOG, errorCallback))
111     {
112         OIC_LOG_V(INFO, TAG, "SQLite debugging log initialized.");
113     }
114
115     int sqlRet;
116     sqlRet = sqlite3_open_v2(!path ? RD_PATH : path, &gRDDB, SQLITE_OPEN_READWRITE, NULL);
117     if (SQLITE_OK != sqlRet)
118     {
119         OIC_LOG(DEBUG, TAG, "RD database file did not open, as no table exists.");
120         OIC_LOG(DEBUG, TAG, "RD creating new table.");
121         sqlRet = sqlite3_open_v2(!path ? RD_PATH : path, &gRDDB,
122                                  SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
123         if (SQLITE_OK == sqlRet)
124         {
125             VERIFY_SQLITE(sqlite3_exec(gRDDB, RD_TABLE, NULL, NULL, NULL));
126             OIC_LOG(DEBUG, TAG, "RD created RD_DEVICE_LIST table.");
127
128             VERIFY_SQLITE(sqlite3_exec(gRDDB, RD_LL_TABLE, NULL, NULL, NULL));
129             OIC_LOG(DEBUG, TAG, "RD created RD_DEVICE_LINK_LIST table.");
130
131             VERIFY_SQLITE(sqlite3_exec(gRDDB, RD_RT_TABLE, NULL, NULL, NULL));
132             OIC_LOG(DEBUG, TAG, "RD created RD_LINK_RT table.");
133
134             VERIFY_SQLITE(sqlite3_exec(gRDDB, RD_IF_TABLE, NULL, NULL, NULL));
135             OIC_LOG(DEBUG, TAG, "RD created RD_LINK_IF table.");
136             sqlRet = SQLITE_OK;
137         }
138     }
139
140     if (sqlRet == SQLITE_OK)
141     {
142         sqlite3_stmt *stmt = 0;
143         VERIFY_SQLITE(sqlite3_prepare_v2 (gRDDB, "PRAGMA foreign_keys = ON;", -1, &stmt, NULL));
144
145         if (SQLITE_DONE != sqlite3_step(stmt))
146         {
147             sqlite3_finalize(stmt);
148             return OC_STACK_ERROR;
149         }
150
151         VERIFY_SQLITE(sqlite3_finalize(stmt));
152     }
153
154     return OC_STACK_OK;
155 }
156
157 OCStackResult OCRDDatabaseClose()
158 {
159     CHECK_DATABASE_INIT;
160     VERIFY_SQLITE(sqlite3_close_v2(gRDDB));
161     return OC_STACK_OK;
162 }
163
164 static int storeResourceType(char **link, size_t size, uint8_t rowid)
165 {
166     int res = 1;
167     VERIFY_SQLITE(sqlite3_exec(gRDDB, "BEGIN TRANSACTION", NULL, NULL, NULL));
168
169     const char *insertRT = "INSERT INTO RD_LINK_RT VALUES(?, ?)";
170     sqlite3_stmt *stmtRT = 0;
171
172     for (size_t i = 0; i < size; i++)
173     {
174         VERIFY_SQLITE(sqlite3_prepare_v2(gRDDB, insertRT, strlen(insertRT) + 1, &stmtRT, NULL));
175         if (link[i])
176         {
177             VERIFY_SQLITE(sqlite3_bind_text(stmtRT, rt_value_index, link[i],
178                                             strlen(link[i]), SQLITE_STATIC));
179
180             VERIFY_SQLITE(sqlite3_bind_int(stmtRT, rt_link_id_index, rowid));
181         }
182         if (sqlite3_step(stmtRT) != SQLITE_DONE)
183         {
184             sqlite3_exec(gRDDB, "ROLLBACK", NULL, NULL, NULL);
185             sqlite3_finalize(stmtRT);
186             return res;
187         }
188     }
189
190     VERIFY_SQLITE(sqlite3_finalize(stmtRT));
191
192     VERIFY_SQLITE(sqlite3_exec(gRDDB, "COMMIT", NULL, NULL, NULL));
193     res = SQLITE_OK;
194
195     return res;
196 }
197
198
199 static int storeInterfaceType(char **link, size_t size, uint8_t rowid)
200 {
201     int res = 1;
202
203     VERIFY_SQLITE(sqlite3_exec(gRDDB, "BEGIN TRANSACTION", NULL, NULL, NULL));
204
205     const char *insertIF = "INSERT INTO RD_LINK_IF VALUES(?, ?)";
206     sqlite3_stmt *stmtIF = 0;
207
208     for (size_t i = 0; i < size; i++)
209     {
210         VERIFY_SQLITE(sqlite3_prepare_v2(gRDDB, insertIF, strlen(insertIF) + 1, &stmtIF, NULL));
211
212         if (link[i])
213         {
214             VERIFY_SQLITE(sqlite3_bind_text(stmtIF, if_value_index, link[i], strlen(link[i]), SQLITE_STATIC));
215             VERIFY_SQLITE(sqlite3_bind_int(stmtIF, if_link_id_index, rowid));
216         }
217         if (sqlite3_step(stmtIF) != SQLITE_DONE)
218         {
219             sqlite3_exec(gRDDB, "ROLLBACK", NULL, NULL, NULL);
220             res = sqlite3_finalize(stmtIF);
221             return res;
222         }
223     }
224     VERIFY_SQLITE(sqlite3_finalize(stmtIF));
225
226     VERIFY_SQLITE(sqlite3_exec(gRDDB, "COMMIT", NULL, NULL, NULL));
227     res = SQLITE_OK;
228
229     return res;
230 }
231
232 static int storeLinkPayload(OCRepPayload *rdPayload, int64_t rowid)
233 {
234     int res = 1 ;
235     size_t j = 0;
236
237     /*
238      * Iterate over the properties manually rather than OCRepPayloadGetPropObjectArray to avoid
239      * the clone since we want to insert the 'ins' values into the payload.
240      */
241     OCRepPayloadValue *links;
242     for (links = rdPayload->values; links; links = links->next)
243     {
244         if (0 == strcmp(links->name, OC_RSRVD_LINKS))
245         {
246             if (links->type != OCREP_PROP_ARRAY || links->arr.type != OCREP_PROP_OBJECT)
247             {
248                 links = NULL;
249             }
250             break;
251         }
252     }
253     if (links != NULL)
254     {
255         const char *insertDeviceLLList = "INSERT INTO RD_DEVICE_LINK_LIST VALUES(?,?,?,?,?,?,?,?)";
256         sqlite3_stmt *stmt = 0;
257
258         for (size_t i = 0; i < links->arr.dimensions[0]; i++)
259         {
260             VERIFY_SQLITE(sqlite3_prepare_v2(gRDDB, insertDeviceLLList, strlen(insertDeviceLLList) + 1, &stmt, NULL));
261             VERIFY_SQLITE(sqlite3_exec(gRDDB, "BEGIN TRANSACTION", NULL, NULL, NULL));
262
263             OCRepPayload *link = links->arr.objArray[i];
264             char *uri = NULL;
265             if (OCRepPayloadGetPropString(link, OC_RSRVD_HREF, &uri))
266             {
267                 VERIFY_SQLITE(sqlite3_bind_text(stmt, uri_index, uri, strlen(uri), SQLITE_STATIC));
268             }
269
270             OCRepPayload *p = NULL;
271             if (OCRepPayloadGetPropObject(link, OC_RSRVD_POLICY, &p))
272             {
273                 int64_t bm = 0;
274                 if (OCRepPayloadGetPropInt(p, OC_RSRVD_BITMAP, &bm))
275                 {
276                     VERIFY_SQLITE(sqlite3_bind_int(stmt, p_index, bm));
277                 }
278             }
279
280             size_t mtDim[MAX_REP_ARRAY_DEPTH] = {0};
281             char **mediaType = NULL;
282             if (OCRepPayloadGetStringArray(link, OC_RSRVD_MEDIA_TYPE, &mediaType, mtDim))
283             {
284                 VERIFY_SQLITE(sqlite3_bind_text(stmt, mt_index, mediaType[0], strlen(mediaType[0]), SQLITE_STATIC));
285             }
286
287             VERIFY_SQLITE(sqlite3_bind_int(stmt, d_index, rowid));
288
289             size_t rtDim[MAX_REP_ARRAY_DEPTH] = {0};
290             char **rt = NULL;
291             OCRepPayloadGetStringArray(link, OC_RSRVD_RESOURCE_TYPE, &rt, rtDim);
292
293             size_t itfDim[MAX_REP_ARRAY_DEPTH] = {0};
294             char **itf = NULL;
295             OCRepPayloadGetStringArray(link, OC_RSRVD_INTERFACE, &itf, itfDim);
296
297             if (sqlite3_step(stmt) != SQLITE_DONE)
298             {
299                 sqlite3_exec(gRDDB, "ROLLBACK", NULL, NULL, NULL);
300                 sqlite3_finalize(stmt);
301                 return res;
302             }
303             VERIFY_SQLITE(sqlite3_exec(gRDDB, "COMMIT", NULL, NULL, NULL));
304
305             int64_t ins = sqlite3_last_insert_rowid(gRDDB);
306             if (!OCRepPayloadSetPropInt(link, OC_RSRVD_INS, ins))
307             {
308                 OIC_LOG_V(ERROR, TAG, "Error setting 'ins' value");
309                 return OC_STACK_ERROR;
310             }
311             VERIFY_SQLITE(storeResourceType(rt, rtDim[0], ins));
312             VERIFY_SQLITE(storeInterfaceType(itf, itfDim[0], ins));
313             OICFree(uri);
314             OCPayloadDestroy((OCPayload *)p);
315             for (j = 0; j < mtDim[0]; j++)
316             {
317                 OICFree(mediaType[j]);
318             }
319             OICFree(mediaType);
320
321             for (j = 0; j < rtDim[0]; j++)
322             {
323                 OICFree(rt[j]);
324             }
325             OICFree(rt);
326
327             for (j = 0; j < itfDim[0]; j++)
328             {
329                 OICFree(itf[j]);
330             }
331             OICFree(itf);
332
333         }
334
335         VERIFY_SQLITE(sqlite3_finalize(stmt));
336         res = SQLITE_OK;
337     }
338     return res;
339 }
340
341 OCStackResult OCRDDatabaseStoreResources(OCRepPayload *payload, const OCDevAddr *address)
342 {
343     CHECK_DATABASE_INIT;
344
345     VERIFY_SQLITE(sqlite3_exec(gRDDB, "BEGIN TRANSACTION", NULL, NULL, NULL));
346     const char *insertDeviceList = "INSERT INTO RD_DEVICE_LIST VALUES(?,?,?,?)";
347     sqlite3_stmt *stmt = 0;
348     VERIFY_SQLITE(sqlite3_prepare_v2(gRDDB, insertDeviceList, strlen(insertDeviceList) + 1, &stmt, NULL));
349
350     char *deviceid = NULL;
351     if (OCRepPayloadGetPropString(payload, OC_RSRVD_DEVICE_ID, &deviceid))
352     {
353         VERIFY_SQLITE(sqlite3_bind_text(stmt, device_index, deviceid, strlen(deviceid), SQLITE_STATIC));
354     }
355
356     int64_t ttl = 0;
357     if (OCRepPayloadGetPropInt(payload, OC_RSRVD_DEVICE_TTL, &ttl))
358     {
359         VERIFY_SQLITE(sqlite3_bind_int(stmt, ttl_index, ttl));
360     }
361
362     char rdAddress[MAX_URI_LENGTH];
363     snprintf(rdAddress, MAX_URI_LENGTH, "%s:%d", address->addr, address->port);
364     OIC_LOG_V(DEBUG, TAG, "Address: %s", rdAddress);
365     VERIFY_SQLITE(sqlite3_bind_text(stmt, address_index, rdAddress, strlen(rdAddress), SQLITE_STATIC));
366
367     if (sqlite3_step(stmt) != SQLITE_DONE)
368     {
369         sqlite3_exec(gRDDB, "ROLLBACK", NULL, NULL, NULL);
370         sqlite3_finalize(stmt);
371         return OC_STACK_ERROR;
372     }
373     VERIFY_SQLITE(sqlite3_finalize(stmt));
374
375     VERIFY_SQLITE(sqlite3_exec(gRDDB, "COMMIT", NULL, NULL, NULL));
376
377     int64_t rowid = sqlite3_last_insert_rowid(gRDDB);
378     if (rowid)
379     {
380         VERIFY_SQLITE(storeLinkPayload(payload, rowid));
381     }
382     OICFree(deviceid);
383     return OC_STACK_OK;
384 }
385
386 OCStackResult OCRDDatabaseDeleteResources(const char *deviceId, const uint8_t *instanceIds, uint8_t nInstanceIds)
387 {
388     CHECK_DATABASE_INIT;
389
390     VERIFY_SQLITE(sqlite3_exec(gRDDB, "BEGIN TRANSACTION", NULL, NULL, NULL));
391     sqlite3_stmt *stmt = 0;
392     if (!instanceIds || !nInstanceIds)
393     {
394         char *delDevice = "DELETE FROM RD_DEVICE_LIST WHERE "XSTR(OC_RSRVD_DEVICE_ID)" = ?";
395         VERIFY_SQLITE(sqlite3_prepare_v2(gRDDB, delDevice, strlen(delDevice) + 1, &stmt, NULL));
396
397         VERIFY_SQLITE(sqlite3_bind_text(stmt, 1, deviceId, strlen(deviceId), SQLITE_STATIC));
398     }
399     else
400     {
401         const char pre[] = "DELETE FROM RD_DEVICE_LINK_LIST "
402             "WHERE ins IN ("
403             "SELECT RD_DEVICE_LINK_LIST.ins FROM RD_DEVICE_LINK_LIST "
404             "INNER JOIN RD_DEVICE_LIST ON RD_DEVICE_LINK_LIST.DEVICE_ID=RD_DEVICE_LIST.ID "
405             "WHERE RD_DEVICE_LIST.di = ? AND RD_DEVICE_LINK_LIST.ins IN (";
406         size_t inLen = nInstanceIds + (nInstanceIds - 1);
407         const char post[] = "))";
408         size_t len = sizeof(pre) + inLen + sizeof(post);
409         char *delResource = OICCalloc(len, 1);
410         if (!delResource)
411         {
412             OIC_LOG(ERROR, TAG, "SQL query is NULL");
413             return OC_STACK_ERROR;
414         }
415         OICStrcat(delResource, len, pre);
416         OICStrcat(delResource, len, "?");
417         for (uint8_t i = 1; i < nInstanceIds; ++i)
418         {
419             OICStrcat(delResource, len, ",?");
420         }
421         OICStrcat(delResource, len, post);
422         int prepareResult = sqlite3_prepare_v2(gRDDB, delResource, strlen(delResource) + 1, &stmt, NULL);
423         OICFree(delResource);
424         VERIFY_SQLITE(prepareResult);
425
426         VERIFY_SQLITE(sqlite3_bind_text(stmt, 1, deviceId, strlen(deviceId), SQLITE_STATIC));
427         for (uint8_t i = 0; i < nInstanceIds; ++i)
428         {
429             VERIFY_SQLITE(sqlite3_bind_int(stmt, 2 + i, instanceIds[i]));
430         }
431     }
432     if (sqlite3_step(stmt) != SQLITE_DONE)
433     {
434         sqlite3_exec(gRDDB, "ROLLBACK", NULL, NULL, NULL);
435         sqlite3_finalize(stmt);
436         return OC_STACK_ERROR;
437     }
438     VERIFY_SQLITE(sqlite3_finalize(stmt));
439     VERIFY_SQLITE(sqlite3_exec(gRDDB, "COMMIT", NULL, NULL, NULL));
440
441     return OC_STACK_OK;
442 }
443
444 #endif