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