• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Relational Store Development (C/C++)
2
3
4## When to Use
5
6The **RelationalStore** module provides a complete mechanism for local database management. You can use the APIs to add, delete, modify, and query data, and execute SQL statements in complex scenarios.
7
8
9## Basic Concepts
10
11- **Predicates**: a representation of the property or feature of a data entity, or the relationship between data entities, used to define operation conditions.
12
13- **ResultSet**: a set of query results, which allows access to the required data in flexible modes.
14
15
16## Constraints
17
18- By default, the Write Ahead Log (WAL) and the **FULL** flushing mode are used.
19
20- A maximum of four connection pools are used for read operations.
21
22- To ensure data accuracy, only one write operation is allowed at a time.
23
24- Once an application is uninstalled, related database files and temporary files are automatically deleted from the device.
25
26- Before using the device-cloud sync APIs added in API version 11, ensure that the cloud service is available.
27
28
29## Available APIs
30
31For details about the interfaces, see [RDB](../reference/apis-arkdata/_r_d_b.md).
32
33| API| Description|
34| -------- | -------- |
35| OH_Rdb_GetOrOpen(const OH_Rdb_Config *config, int *errCode) | Obtains an **OH_Rdb_Store** instance for RDB store operations.|
36| OH_Rdb_Execute(OH_Rdb_Store *store, const char *sql) | Executes an SQL statement that contains specified arguments but returns no value.|
37| OH_Rdb_Insert(OH_Rdb_Store *store, const char *table, OH_VBucket *valuesBucket) | Inserts a row of data into a table.|
38| OH_Rdb_Update(OH_Rdb_Store *store, OH_VBucket *valuesBucket, OH_Predicates *predicates) | Updates data in an RDB store. |
39| OH_Rdb_Delete(OH_Rdb_Store *store, OH_Predicates *predicates) | Deletes data from an RDB store. |
40| OH_Rdb_Query(OH_Rdb_Store *store, OH_Predicates *predicates, const char *const *columnNames, int length) | Queries data in an RDB store. |
41| OH_Rdb_DeleteStore(const OH_Rdb_Config *config) | Deletes an RDB store.|
42| OH_VBucket_PutAsset(OH_VBucket *bucket, const char *field, Rdb_Asset *value) | Puts an RDB asset into an **OH_VBucket** object.|
43| OH_VBucket_PutAssets(OH_VBucket *bucket, const char *field, Rdb_Asset *value, uint32_t count) | Puts RDB assets into an **OH_VBucket** object.|
44| OH_Rdb_SetDistributedTables(OH_Rdb_Store *store, const char *tables[], uint32_t count, Rdb_DistributedType type, const Rdb_DistributedConfig *config) | Sets distributed database tables.|
45| OH_Rdb_FindModifyTime(OH_Rdb_Store *store, const char *tableName, const char *columnName, OH_VObject *values) | Obtains the last modification time of the data in the specified column of a table. |
46| OH_Rdb_CloudSync(OH_Rdb_Store *store, Rdb_SyncMode mode, const char *tables[], uint32_t count, const Rdb_ProgressObserver *observer) | Manually performs device-cloud sync for a table. The cloud service must be available. |
47| int OH_Data_Asset_SetName(Data_Asset *asset, const char *name) | Sets the name for a data asset.|
48| int OH_Data_Asset_SetUri(Data_Asset *asset, const char *uri) | Sets the absolute path for a data asset.|
49| int OH_Data_Asset_SetPath(Data_Asset *asset, const char *path) | Sets the relative path in the application sandbox directory for a data asset.|
50| int OH_Data_Asset_SetCreateTime(Data_Asset *asset, int64_t createTime) | Sets the creation time for a data asset.|
51| int OH_Data_Asset_SetModifyTime(Data_Asset *asset, int64_t modifyTime) | Sets the last modification time for a data asset.|
52| int OH_Data_Asset_SetSize(Data_Asset *asset, size_t size) | Sets the size of a data asset.|
53| int OH_Data_Asset_SetStatus(Data_Asset *asset, Data_AssetStatus status) | Sets the status for a data asset.|
54| int OH_Data_Asset_GetName(Data_Asset *asset, char *name, size_t *length) | Obtains the name of a data asset.|
55| int OH_Data_Asset_GetUri(Data_Asset *asset, char *uri, size_t *length) | Obtains the absolute path of a data asset.|
56| int OH_Data_Asset_GetPath(Data_Asset *asset, char *path, size_t *length) | Obtains the relative path of a data asset.|
57| int OH_Data_Asset_GetCreateTime(Data_Asset *asset, int64_t *createTime) | Obtains the creation time of a data asset.|
58| int OH_Data_Asset_GetModifyTime(Data_Asset *asset, int64_t *modifyTime) | Obtains the last modification time of a data asset.|
59| int OH_Data_Asset_GetSize(Data_Asset *asset, size_t *size) | Obtains the size of a data asset.|
60| int OH_Data_Asset_GetStatus(Data_Asset *asset, Data_AssetStatus *status) | Obtains the status of a data asset.|
61| Data_Asset *OH_Data_Asset_CreateOne() | Creates a data asset instance. When this data asset is no longer needed, use **OH_Data_Asset_DestroyOne** to destroy it. |
62| int OH_Data_Asset_DestroyOne(Data_Asset *asset) | Destroys a data asset instance to reclaim memory.|
63| Data_Asset **OH_Data_Asset_CreateMultiple(uint32_t count) | Creates an instance for multiple data assets. When the instance is no longer required, use **OH_Data_Asset_DestroyMultiple** to destroy it. |
64| int OH_Data_Asset_DestroyMultiple(Data_Asset **assets, uint32_t count) | Destroys multiple data assets to reclaim memory.|
65| int OH_Rdb_Subscribe(OH_Rdb_Store *store, Rdb_SubscribeType type, const Rdb_DataObserver *observer) | Registers an observer for an RDB store. When the data in the distributed database changes, a callback will be invoked to return the data change.|
66| int OH_Rdb_Unsubscribe(OH_Rdb_Store *store, Rdb_SubscribeType type, const Rdb_DataObserver *observer) | Unregisters the observer of the specified type.|
67| int OH_Rdb_SubscribeAutoSyncProgress(OH_Rdb_Store *store, const Rdb_ProgressObserver *observer) | Subscribes to the auto sync process of an RDB store. The registered callback will be invoked to return the auto sync progress received. |
68| int OH_Rdb_UnsubscribeAutoSyncProgress(OH_Rdb_Store *store, const Rdb_ProgressObserver *observer) | Unsubscribes from the auto sync process of an RDB store.|
69
70
71## How to Develop
72
73**Adding the Dynamic Link Library**
74
75Add the following library to **CMakeLists.txt**:
76
77```txt
78libnative_rdb_ndk.z.so
79```
80
81**Including Header Files**
82
83```c++
84#include <database/data/data_asset.h>
85#include <database/rdb/oh_cursor.h>
86#include <database/rdb/oh_predicates.h>
87#include <database/rdb/oh_value_object.h>
88#include <database/rdb/oh_values_bucket.h>
89#include <database/rdb/relational_store.h>
90#include <database/rdb/relational_store_error_code.h>
91```
92
931. Obtain an **OH_Rdb_Store** instance and create a database file.
94
95   The **dataBaseDir** variable specifies the application sandbox path. In the stage model, you are advised to use the database directory. For details, see the **databaseDir** attribute of [Context](../reference/apis-ability-kit/js-apis-inner-application-context.md). The FA model does not provide any API for obtaining the database sandbox path. Use the application directory instead. For details, see **getFilesDir** of [Context](../reference/apis-ability-kit/js-apis-inner-app-context.md).
96
97   **area** indicates the security level of the directory for database files. For details, see [contextConstant](../reference/apis-ability-kit/js-apis-app-ability-contextConstant.md).
98
99   During development, you need to implement the conversion from **AreaMode** to **Rdb_SecurityArea**.
100
101   Example:
102
103   ```c
104   // Create an OH_Rdb_Config object.
105   OH_Rdb_Config config;
106   // The path is the application sandbox path.
107   config.dataBaseDir = "xxx";
108   // Database file name.
109   config.storeName = "RdbTest.db";
110   // Application bundle name.
111   config.bundleName = "xxx";
112   // Module name.
113   config.moduleName = "xxx";
114   // Security level of the database file.
115   config.securityLevel = OH_Rdb_SecurityLevel::S1;
116   // Whether the database is encrypted.
117   config.isEncrypt = false;
118   // Memory size occupied by config.
119   config.selfSize = sizeof(OH_Rdb_Config);
120   // Security level of the directory for storing the database file.
121   config.area = RDB_SECURITY_AREA_EL1;
122
123   int errCode = 0;
124   // Obtain an OH_Rdb_Store instance.
125   OH_Rdb_Store *store_ = OH_Rdb_GetOrOpen(&config, &errCode);
126   ```
127
1282. Call **OH_Rdb_Execute** to create a table, and call **OH_Rdb_Insert** to insert data to the table. <br>Example:
129
130   ```c
131   char createTableSql[] = "CREATE TABLE IF NOT EXISTS EMPLOYEE (ID INTEGER PRIMARY KEY AUTOINCREMENT, NAME TEXT NOT NULL, "
132                           "AGE INTEGER, SALARY REAL, CODES BLOB)";
133   // Create a table.
134   OH_Rdb_Execute(store_, createTableSql);
135
136   // Create a key-value (KV) pair instance.
137   OH_VBucket *valueBucket = OH_Rdb_CreateValuesBucket();
138   valueBucket->putText(valueBucket, "NAME", "Lisa");
139   valueBucket->putInt64(valueBucket, "AGE", 18);
140   valueBucket->putReal(valueBucket, "SALARY", 100.5);
141   uint8_t arr[] = {1, 2, 3, 4, 5};
142   int len = sizeof(arr) / sizeof(arr[0]);
143   valueBucket->putBlob(valueBucket, "CODES", arr, len);
144   // Insert data.
145   int rowId = OH_Rdb_Insert(store_, "EMPLOYEE", valueBucket);
146   // Destroy the KV pair instance.
147   valueBucket->destroy(valueBucket);
148   ```
149
150   > **NOTE**
151   >
152   > **RelationalStore** does not provide explicit flush operations for data persistence. The **insert()** API stores data persistently.
153
1543. Modify or delete data based on the conditions specified by **OH_Predicates**.
155
156   Call **OH_Rdb_Update** to modify data, and call **OH_Rdb_Delete** to delete data. <br>Example:
157
158   ```c
159   // Modify data.
160   OH_VBucket *valueBucket = OH_Rdb_CreateValuesBucket();
161   valueBucket->putText(valueBucket, "NAME", "Rose");
162   valueBucket->putInt64(valueBucket, "AGE", 22);
163   valueBucket->putReal(valueBucket, "SALARY", 200.5);
164   uint8_t arr[] = {1, 2, 3, 4, 5};
165   int len = sizeof(arr) / sizeof(arr[0]);
166   valueBucket->putBlob(valueBucket, "CODES", arr, len);
167
168   OH_Predicates *predicates = OH_Rdb_CreatePredicates("EMPLOYEE");
169   OH_VObject *valueObject = OH_Rdb_CreateValueObject();
170   const char *name = "Lisa";
171   valueObject->putText(valueObject, name);
172   predicates->equalTo(predicates, "NAME", valueObject)->andOperate(predicates);
173   uint32_t count = 1;
174   double salary = 100.5;
175   valueObject->putDouble(valueObject, &salary, count);
176   predicates->equalTo(predicates, "SALARY", valueObject);
177
178   int changeRows = OH_Rdb_Update(store_, valueBucket, predicates);
179   valueObject->destroy(valueObject);
180   valueBucket->destroy(valueBucket);
181   predicates->destroy(predicates);
182   ```
183
184   ```c
185   // Delete data.
186   OH_Predicates *predicates = OH_Rdb_CreatePredicates("EMPLOYEE");
187   OH_VObject *valueObject = OH_Rdb_CreateValueObject();
188   const char *name = "Lisa";
189   valueObject->putText(valueObject, name);
190   predicates->equalTo(predicates, "NAME", valueObject);
191   int deleteRows = OH_Rdb_Delete(store_, predicates);
192   valueObject->destroy(valueObject);
193   predicates->destroy(predicates);
194   ```
195
1964. Query data based on the conditions specified by **OH_Predicates**.
197
198   Call **OH_Rdb_Query** to query data. The data obtained is returned in an **OH_Cursor** object. <br>Example:
199
200   ```c
201   OH_Predicates *predicates = OH_Rdb_CreatePredicates("EMPLOYEE");
202
203   const char *columnNames[] = {"NAME", "AGE"};
204   int len = sizeof(columnNames) / sizeof(columnNames[0]);
205   OH_Cursor *cursor = OH_Rdb_Query(store_, predicates, columnNames, len);
206
207   int columnCount = 0;
208   cursor->getColumnCount(cursor, &columnCount);
209
210   // OH_Cursor is a cursor of a data set. By default, the cursor points to the -1st record. Valid data starts from 0.
211   int64_t age;
212   while (cursor->goToNextRow(cursor) == OH_Rdb_ErrCode::RDB_OK) {
213       cursor->getInt64(cursor, 1, &age);
214   }
215
216   // Destroy the OH_Predicates instance.
217   predicates->destroy(predicates);
218   // Destroy the result set.
219   cursor->destroy(cursor);
220   ```
221
2225. Insert data assets into a table.
223
224   ```c
225   // If the column attribute is a single asset, use asset in the SQL statements. If the column attribute is multiple assets, use assets in the SQL statements.
226   char createAssetTableSql[] = "CREATE TABLE IF NOT EXISTS asset_table (id INTEGER PRIMARY KEY AUTOINCREMENT, data1 asset, data2 assets );";
227   errCode = OH_Rdb_Execute(storeTestRdbStore_, createAssetTableSql);
228   Data_Asset *asset = OH_Data_Asset_CreateOne();
229   OH_Data_Asset_SetName(asset, "name0");
230   OH_Data_Asset_SetUri(asset, "uri0");
231   OH_Data_Asset_SetPath(asset, "path0");
232   OH_Data_Asset_SetCreateTime(asset, 1);
233   OH_Data_Asset_SetModifyTime(asset, 1);
234   OH_Data_Asset_SetSize(asset, 1);
235   OH_Data_Asset_SetStatus(asset, Data_AssetStatus::ASSET_NORMAL);
236   errCode = OH_VBucket_PutAsset(valueBucket, "data1", asset);
237
238   Data_Asset **assets = OH_Data_Asset_CreateMultiple(2);
239
240   OH_Data_Asset_SetName(assets[0], "name0");
241   OH_Data_Asset_SetUri(assets[0], "uri0");
242   OH_Data_Asset_SetPath(assets[0], "path0");
243   OH_Data_Asset_SetCreateTime(assets[0], 1);
244   OH_Data_Asset_SetModifyTime(assets[0], 1);
245   OH_Data_Asset_SetSize(assets[0], 1);
246   OH_Data_Asset_SetStatus(assets[0], Data_AssetStatus::ASSET_NORMAL);
247
248   OH_Data_Asset_SetName(assets[1], "name1");
249   OH_Data_Asset_SetUri(assets[1], "uri1");
250   OH_Data_Asset_SetPath(assets[1], "path1");
251   OH_Data_Asset_SetCreateTime(assets[1], 1);
252   OH_Data_Asset_SetModifyTime(assets[1], 1);
253   OH_Data_Asset_SetSize(assets[1], 1);
254   OH_Data_Asset_SetStatus(assets[1], Data_AssetStatus::ASSET_NORMAL);
255
256   errCode = OH_VBucket_PutAssets(valueBucket, "data2", assets, assetsCount);
257   int rowID = OH_Rdb_Insert(cursorTestRdbStore_, table, valueBucket);
258   // Destroy Data_Asset* and Data_Asset**.
259   OH_Data_Asset_DestroyMultiple(assets, 2);
260   OH_Data_Asset_DestroyOne(asset);
261   ```
262
2636. Read data assets from the result set.
264
265   ```c
266   OH_Predicates *predicates = OH_Rdb_CreatePredicates("asset_table");
267
268   OH_Cursor *cursor = OH_Rdb_Query(cursorTestRdbStore_, predicates, NULL, 0);
269   cursor->goToNextRow(cursor);
270
271   uint32_t assetCount = 0;
272   // assetCount is an output parameter that indicates the number of assets in this column.
273   errCode = cursor->getAssets(cursor, 2, nullptr, &assetCount);
274   Data_Asset **assets = OH_Data_Asset_CreateMultiple(assetCount);
275   errCode = cursor->getAssets(cursor, 2, assets, &assetCount);
276   Data_Asset *asset = assets[1];
277
278   char name[10] = "";
279   size_t nameLength = 10;
280   errCode = OH_Data_Asset_GetName(asset, name, &nameLength);
281
282   char uri[10] = "";
283   size_t uriLength = 10;
284   errCode = OH_Data_Asset_GetUri(asset, uri, &uriLength);
285
286   char path[10] = "";
287   size_t pathLength = 10;
288   errCode = OH_Data_Asset_GetPath(asset, path, &pathLength);
289
290   int64_t createTime = 0;
291   errCode = OH_Data_Asset_GetCreateTime(asset, &createTime);
292
293   int64_t modifyTime = 0;
294   errCode = OH_Data_Asset_GetModifyTime(asset, &modifyTime);
295
296   size_t size = 0;
297   errCode = OH_Data_Asset_GetSize(asset, &size);
298
299   Data_AssetStatus status = Data_AssetStatus::ASSET_NULL;
300   errCode = OH_Data_Asset_GetStatus(asset, &status);
301
302   predicates->destroy(predicates);
303   OH_Data_Asset_DestroyMultiple(assets, assetCount);
304   cursor->destroy(cursor);
305   ```
306
3077. Obtain the last modification time of data.
308
309   Call **OH_Rdb_FindModifyTime** to obtain the last modification time of data in the specified column of a table. This API returns an **OH_Cursor** object with two columns of data. The first column is the primary key or row ID, and the second column is the last modification time. <br>Example:
310
311   ```c
312   OH_VObject *values = OH_Rdb_CreateValueObject();
313   int64_t keys[] = { 1 };
314   values->putInt64(values, keys, 1);
315   OH_Cursor *cursor;
316   cursor = OH_Rdb_FindModifyTime(storeTestRdbStore_, "EMPLOYEE", "ROWID", values);
317   ```
318
3198. Create distributed tables.
320
321   Call **OH_Rdb_SetDistributedTables** to set distributed tables for the table (created by using **OH_Rdb_Execute**). Before using this API, ensure that the cloud service is available. <br>Example:
322
323   ```c
324   constexpr int TABLE_COUNT = 1;
325   const char *table[TABLE_COUNT];
326   table[0] = "EMPLOYEE";
327   int errcode = OH_Rdb_SetDistributedTables(storeTestRdbStore_, table, TABLE_COUNT, Rdb_DistributedType::DISTRIBUTED_CLOUD, &config);
328   ```
329
3309. Manually perform device-cloud sync for the distributed tables.
331
332   Call **OH_Rdb_CloudSync** to perform device-cloud sync for the tables. Before using this API, ensure that the cloud service is available. <br>Example:
333
334   ```c
335   // Define a callback.
336   void CloudSyncObserverCallback(void *context, Rdb_ProgressDetails *progressDetails)
337   {
338    // Do something.
339   }
340   const Rdb_ProgressObserver observer = { .context = nullptr, .callback = CloudSyncObserverCallback };
341   OH_Rdb_CloudSync(storeTestRdbStore_, Rdb_SyncMode::SYNC_MODE_TIME_FIRST, table, TABLE_COUNT, &observer);
342   ```
343
34410. Register a data observer for the specified event type for an RDB store. When the data changes, the registered callback will be invoked to process the observation.
345
346    Call **OH_Rdb_Subscribe** to subscribe to data changes. Before using this API, ensure that the cloud service is available. <br>Example:
347
348    ```c
349    // Define a callback.
350    void RdbSubscribeBriefCallback(void *context, const char *values[], uint32_t count)
351    {
352    // do something
353    }
354    Rdb_BriefObserver briefObserver;
355    const Rdb_BriefObserver briefObserver = { .context = nullptr, .callback = RdbSubscribeBriefCallback };
356    OH_Rdb_Subscribe(storeTestRdbStore_, Rdb_SubscribeType::RDB_SUBSCRIBE_TYPE_CLOUD, &briefObserver);
357    ```
358
35911. Unsubscribe from the events of the specified type for an RDB store. After that, the callback will not be invoked to process the observation.
360
361     Call **OH_Rdb_Unsubscribe** to unsubscribe from data changes. Before using this API, ensure that the cloud service is available. <br>Example:
362
363     ```c
364     // Define a callback.
365     void RdbSubscribeBriefCallback(void *context, const char *values[], uint32_t count)
366     {
367     // do something
368     }
369     Rdb_BriefObserver briefObserver = RdbSubscribeBriefCallback;
370     const Rdb_DataObserver briefObs = { .context = nullptr, .callback.briefObserver = briefObserver };
371     OH_Rdb_Unsubscribe(storeTestRdbStore_, Rdb_SubscribeType::RDB_SUBSCRIBE_TYPE_CLOUD, &briefObs);
372     ```
373
37412. Register an observer for auto sync progress of an RDB store. When auto sync is performed on the RDB store, the registered callback will be invoked to process the observation.
375
376     Call **OH_Rdb_SubscribeAutoSyncProgress** to subscribe to the auto sync progress. Before using this API, ensure that the cloud service is available. <br>Example:
377
378     ```c
379     // Define a callback.
380     void RdbProgressObserverCallback(void *context, Rdb_ProgressDetails *progressDetails)
381     {
382     // do something
383     }
384     const Rdb_ProgressObserver observer = { .context = nullptr, .callback = RdbProgressObserverCallback };
385     OH_Rdb_SubscribeAutoSyncProgress(storeTestRdbStore_, &observer);
386     ```
387
38813. Unsubscribe from the auto sync progress from an RDB store. After that, the callback will not be invoked to process the observation.
389
390     Call **OH_Rdb_UnsubscribeAutoSyncProgress** to unsubscribe from the auto sync progress. Before using this API, ensure that the cloud service is available. <br>Example:
391
392     ```c
393     // Define a callback.
394     void RdbProgressObserverCallback(void *context, Rdb_ProgressDetails *progressDetails)
395     {
396     // do something
397     }
398     const Rdb_ProgressObserver observer = { .context = nullptr, .callback = RdbProgressObserverCallback };
399     OH_Rdb_UnsubscribeAutoSyncProgress(storeTestRdbStore_, &observer);
400     ```
401
40214. Delete an RDB store.
403
404     Call **OH_Rdb_DeleteStore** to delete the RDB store and related database file. <br>Example:
405
406     ```c
407     // Close the database instance.
408     OH_Rdb_CloseStore(store_);
409     // Delete the database file.
410     OH_Rdb_DeleteStore(&config);
411     ```
412
413
414
415
416
417
418