1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 
16 #include "sqlite_store_executor_impl.h"
17 
18 #include "check_common.h"
19 #include "rd_db_constant.h"
20 #include "doc_errno.h"
21 #include "document_key.h"
22 #include "rd_log_print.h"
23 #include "rd_sqlite_utils.h"
24 
25 namespace DocumentDB {
26 constexpr const uint8_t KEY_TYPE = uint8_t(DocIdType::STRING);
CreateDatabase(const std::string & path,const DBConfig & config,sqlite3 * & db)27 int SqliteStoreExecutorImpl::CreateDatabase(const std::string &path, const DBConfig &config, sqlite3 *&db)
28 {
29     if (db != nullptr) {
30         return -E_INVALID_ARGS;
31     }
32 
33     int errCode = RDSQLiteUtils::CreateDataBase(path, 0, db);
34     if (errCode != E_OK || db == nullptr) {
35         GLOGE("Open or create database failed. %d", errCode);
36         return errCode;
37     }
38 
39     std::string pageSizeSql = "PRAGMA page_size=" + std::to_string(config.GetPageSize() * 1024);
40     errCode = RDSQLiteUtils::ExecSql(db, pageSizeSql);
41     if (errCode != E_OK) {
42         GLOGE("Set db page size failed. %d", errCode);
43         goto END;
44     }
45 
46     errCode = RDSQLiteUtils::ExecSql(db, "PRAGMA journal_mode=WAL;");
47     if (errCode != E_OK) {
48         GLOGE("Set db journal_mode failed. %d", errCode);
49         goto END;
50     }
51 
52     errCode = RDSQLiteUtils::ExecSql(db, "CREATE TABLE IF NOT EXISTS grd_meta (key BLOB PRIMARY KEY, value BLOB);");
53     if (errCode != E_OK) {
54         GLOGE("Create meta table failed. %d", errCode);
55         goto END;
56     }
57 
58     return E_OK;
59 
60 END:
61     sqlite3_close_v2(db);
62     db = nullptr;
63     return errCode;
64 }
65 
SqliteStoreExecutorImpl(sqlite3 * handle)66 SqliteStoreExecutorImpl::SqliteStoreExecutorImpl(sqlite3 *handle) : dbHandle_(handle) {}
67 
~SqliteStoreExecutorImpl()68 SqliteStoreExecutorImpl::~SqliteStoreExecutorImpl()
69 {
70     sqlite3_close_v2(dbHandle_);
71     dbHandle_ = nullptr;
72 }
73 
GetDBConfig(std::string & config)74 int SqliteStoreExecutorImpl::GetDBConfig(std::string &config)
75 {
76     std::string dbConfigKeyStr = "DB_CONFIG";
77     Key dbConfigKey = { dbConfigKeyStr.begin(), dbConfigKeyStr.end() };
78     Value dbConfigVal;
79     int errCode = GetDataByKey("grd_meta", dbConfigKey, dbConfigVal);
80     config.assign(dbConfigVal.begin(), dbConfigVal.end());
81     return errCode;
82 }
83 
SetDBConfig(const std::string & config)84 int SqliteStoreExecutorImpl::SetDBConfig(const std::string &config)
85 {
86     std::string dbConfigKeyStr = "DB_CONFIG";
87     Key dbConfigKey = { dbConfigKeyStr.begin(), dbConfigKeyStr.end() };
88     Value dbConfigVal = { config.begin(), config.end() };
89     return PutData("grd_meta", dbConfigKey, dbConfigVal, false); // dont need to add Key type;
90 }
91 
StartTransaction()92 int SqliteStoreExecutorImpl::StartTransaction()
93 {
94     return RDSQLiteUtils::BeginTransaction(dbHandle_, TransactType::IMMEDIATE);
95 }
96 
Commit()97 int SqliteStoreExecutorImpl::Commit()
98 {
99     return RDSQLiteUtils::CommitTransaction(dbHandle_);
100 }
101 
Rollback()102 int SqliteStoreExecutorImpl::Rollback()
103 {
104     return RDSQLiteUtils::RollbackTransaction(dbHandle_);
105 }
106 
PutData(const std::string & collName,Key & key,const Value & value,bool isNeedAddKeyType)107 int SqliteStoreExecutorImpl::PutData(const std::string &collName, Key &key, const Value &value, bool isNeedAddKeyType)
108 {
109     if (dbHandle_ == nullptr) {
110         return -E_ERROR;
111     }
112     if (isNeedAddKeyType) {
113         key.push_back(KEY_TYPE); // Stitching ID type
114     }
115     std::string sql = "INSERT OR REPLACE INTO '" + collName + "' VALUES (?,?);";
116     int errCode = RDSQLiteUtils::ExecSql(
117         dbHandle_, sql,
118         [key, value](sqlite3_stmt *stmt) {
119             RDSQLiteUtils::BindBlobToStatement(stmt, 1, key);
120             RDSQLiteUtils::BindBlobToStatement(stmt, 2, value);
121             return E_OK;
122         },
123         nullptr);
124     if (errCode != E_OK) {
125         GLOGE("[sqlite executor] Put data failed. err=%d", errCode);
126         if (errCode == -E_ERROR) {
127             GLOGE("Cant find the collection");
128             return -E_INVALID_ARGS;
129         }
130         return errCode;
131     }
132     return E_OK;
133 }
134 
InsertData(const std::string & collName,Key & key,const Value & value,bool isNeedAddKeyType)135 int SqliteStoreExecutorImpl::InsertData(const std::string &collName, Key &key, const Value &value,
136     bool isNeedAddKeyType)
137 {
138     if (dbHandle_ == nullptr) {
139         return -E_ERROR;
140     }
141     if (isNeedAddKeyType) {
142         key.push_back(KEY_TYPE); // Stitching ID type
143     }
144     std::string sql = "INSERT INTO '" + collName + "' VALUES (?,?);";
145     int errCode = RDSQLiteUtils::ExecSql(
146         dbHandle_, sql,
147         [key, value](sqlite3_stmt *stmt) {
148             RDSQLiteUtils::BindBlobToStatement(stmt, 1, key);
149             RDSQLiteUtils::BindBlobToStatement(stmt, 2, value);
150             return E_OK;
151         },
152         nullptr);
153     if (errCode != E_OK) {
154         GLOGE("[sqlite executor] Put data failed. err=%d", errCode);
155         if (errCode == -E_ERROR) {
156             GLOGE("have same ID before");
157             return -E_DATA_CONFLICT;
158         }
159         return errCode;
160     }
161     return E_OK;
162 }
163 
GetDataByKey(const std::string & collName,Key & key,Value & value) const164 int SqliteStoreExecutorImpl::GetDataByKey(const std::string &collName, Key &key, Value &value) const
165 {
166     if (dbHandle_ == nullptr) {
167         GLOGE("Invalid db handle.");
168         return -E_ERROR;
169     }
170     int innerErrorCode = -E_NOT_FOUND;
171     std::string sql = "SELECT value FROM '" + collName + "' WHERE key=?;";
172     int errCode = RDSQLiteUtils::ExecSql(
173         dbHandle_, sql,
174         [key](sqlite3_stmt *stmt) {
175             RDSQLiteUtils::BindBlobToStatement(stmt, 1, key);
176             return E_OK;
177         },
178         [&value, &innerErrorCode](sqlite3_stmt *stmt, bool &isMatchOneData) {
179             RDSQLiteUtils::GetColumnBlobValue(stmt, 0, value);
180             innerErrorCode = E_OK;
181             return E_OK;
182         });
183     if (errCode != E_OK) {
184         GLOGE("[sqlite executor] Get data failed. err=%d", errCode);
185         return errCode;
186     }
187     return innerErrorCode;
188 }
189 
GetDataById(const std::string & collName,Key & key,Value & value) const190 int SqliteStoreExecutorImpl::GetDataById(const std::string &collName, Key &key, Value &value) const
191 {
192     if (dbHandle_ == nullptr) {
193         GLOGE("Invalid db handle.");
194         return -E_ERROR;
195     }
196     key.push_back(KEY_TYPE); // Stitching ID type
197     int innerErrorCode = -E_NOT_FOUND;
198     std::string sql = "SELECT value FROM '" + collName + "' WHERE key=?;";
199     int errCode = RDSQLiteUtils::ExecSql(
200         dbHandle_, sql,
201         [key](sqlite3_stmt *stmt) {
202             RDSQLiteUtils::BindBlobToStatement(stmt, 1, key);
203             return E_OK;
204         },
205         [&value, &innerErrorCode](sqlite3_stmt *stmt, bool &isMatchOneData) {
206             RDSQLiteUtils::GetColumnBlobValue(stmt, 0, value);
207             innerErrorCode = E_OK;
208             return E_OK;
209         });
210     if (errCode != E_OK) {
211         GLOGE("[sqlite executor] Get data failed. err=%d", errCode);
212         return errCode;
213     }
214     return innerErrorCode;
215 }
216 
GeneralInsertSql(const std::string & collName,Key & key,int isIdExist)217 std::string GeneralInsertSql(const std::string &collName, Key &key, int isIdExist)
218 {
219     std::string sqlEqual = "SELECT key, value FROM '" + collName + "' WHERE key=?;";
220     std::string sqlOrder = "SELECT key, value FROM '" + collName + "' ORDER BY KEY;";
221     std::string sqlLarger = "SELECT key, value FROM '" + collName + "' WHERE key>?;";
222     if (isIdExist) {
223         return sqlEqual;
224     } else {
225         return (key.empty()) ? sqlOrder : sqlLarger;
226     }
227 }
228 
AssignValueToData(std::string & keyStr,const std::string & valueStr,std::pair<std::string,std::string> & values,int & innerErrorCode,bool & isMatchOneData)229 void AssignValueToData(std::string &keyStr, const std::string &valueStr, std::pair<std::string, std::string> &values,
230     int &innerErrorCode, bool &isMatchOneData)
231 {
232     keyStr.pop_back(); // get id from really key.
233     values.first = keyStr;
234     values.second = valueStr;
235     innerErrorCode = E_OK;
236     isMatchOneData = true; // this args work in ExecSql fuction
237 }
238 
GetDataByFilter(const std::string & collName,Key & key,const JsonObject & filterObj,std::pair<std::string,std::string> & values,int isIdExist) const239 int SqliteStoreExecutorImpl::GetDataByFilter(const std::string &collName, Key &key, const JsonObject &filterObj,
240     std::pair<std::string, std::string> &values, int isIdExist) const
241 {
242     if (dbHandle_ == nullptr) {
243         GLOGE("Invalid db handle.");
244         return -E_ERROR;
245     }
246     Value keyResult;
247     Value valueResult;
248     bool isFindMatch = false;
249     int innerErrorCode = -E_NOT_FOUND;
250     std::string sql = GeneralInsertSql(collName, key, isIdExist);
251     key.push_back(KEY_TYPE);
252     std::string keyStr(key.begin(), key.end());
253     int errCode = RDSQLiteUtils::ExecSql(
254         dbHandle_, sql,
255         [key](sqlite3_stmt *stmt) {
256             if (!key.empty()) {
257                 RDSQLiteUtils::BindBlobToStatement(stmt, 1, key);
258             }
259             return E_OK;
260         },
261         [&keyResult, &innerErrorCode, &valueResult, &filterObj, &values, &isFindMatch](sqlite3_stmt *stmt,
262             bool &isMatchOneData) {
263             RDSQLiteUtils::GetColumnBlobValue(stmt, 0, keyResult);
264             RDSQLiteUtils::GetColumnBlobValue(stmt, 1, valueResult);
265             std::string keyStr(keyResult.begin(), keyResult.end());
266             std::string valueStr(valueResult.begin(), valueResult.end());
267             JsonObject srcObj = JsonObject::Parse(valueStr, innerErrorCode, true);
268             if (innerErrorCode != E_OK) {
269                 GLOGE("srcObj Parsed failed");
270                 return innerErrorCode;
271             }
272             if (JsonCommon::IsJsonNodeMatch(srcObj, filterObj, innerErrorCode)) {
273                 isFindMatch = true; // this args work in this function
274                 (void)AssignValueToData(keyStr, valueStr, values, innerErrorCode, isMatchOneData);
275                 return E_OK; // match count;
276             }
277             innerErrorCode = E_OK;
278             return E_OK;
279         });
280     if (errCode != E_OK) {
281         GLOGE("[sqlite executor] Get data failed. err=%d", errCode);
282         return errCode;
283     }
284     if (!isFindMatch) {
285         return -E_NOT_FOUND;
286     }
287     return innerErrorCode;
288 }
289 
DelData(const std::string & collName,Key & key)290 int SqliteStoreExecutorImpl::DelData(const std::string &collName, Key &key)
291 {
292     if (dbHandle_ == nullptr) {
293         GLOGE("Invalid db handle.");
294         return -E_ERROR;
295     }
296     key.push_back(KEY_TYPE);
297     int errCode = 0;
298     Value valueRet;
299     if (GetDataByKey(collName, key, valueRet) != E_OK) {
300         return -E_NO_DATA;
301     }
302     std::string sql = "DELETE FROM '" + collName + "' WHERE key=?;";
303     errCode = RDSQLiteUtils::ExecSql(
304         dbHandle_, sql,
305         [key](sqlite3_stmt *stmt) {
306             RDSQLiteUtils::BindBlobToStatement(stmt, 1, key);
307             return E_OK;
308         },
309         nullptr);
310     if (errCode != E_OK) {
311         GLOGE("[sqlite executor] Delete data failed. err=%d", errCode);
312         if (errCode == -E_ERROR) {
313             GLOGE("Cant find the collection");
314             return -E_NO_DATA;
315         }
316     }
317     return errCode;
318 }
319 
CreateCollection(const std::string & name,const std::string & option,bool ignoreExists)320 int SqliteStoreExecutorImpl::CreateCollection(const std::string &name, const std::string &option, bool ignoreExists)
321 {
322     if (dbHandle_ == nullptr) {
323         return -E_ERROR;
324     }
325     std::string collName = RdDBConstant::COLL_PREFIX + name;
326     int errCode = E_OK;
327     bool isExists = IsCollectionExists(collName, errCode);
328     if (errCode != E_OK) {
329         return errCode;
330     }
331 
332     if (isExists) {
333         GLOGW("[sqlite executor] Create collection failed, collection already exists.");
334         return ignoreExists ? E_OK : -E_COLLECTION_CONFLICT;
335     }
336 
337     std::string sql = "CREATE TABLE IF NOT EXISTS '" + collName + "' (key BLOB PRIMARY KEY, value BLOB);";
338     errCode = RDSQLiteUtils::ExecSql(dbHandle_, sql);
339     if (errCode != E_OK) {
340         GLOGE("[sqlite executor] Create collection failed. err=%d", errCode);
341         return errCode;
342     }
343 
344     errCode = SetCollectionOption(name, option);
345     if (errCode != E_OK) {
346         GLOGE("[sqlite executor] Set collection option failed. err=%d", errCode);
347     }
348     return errCode;
349 }
350 
DropCollection(const std::string & name,bool ignoreNonExists)351 int SqliteStoreExecutorImpl::DropCollection(const std::string &name, bool ignoreNonExists)
352 {
353     if (dbHandle_ == nullptr) {
354         return -E_ERROR;
355     }
356 
357     std::string collName = RdDBConstant::COLL_PREFIX + name;
358     if (!ignoreNonExists) {
359         int errCode = E_OK;
360         bool isExists = IsCollectionExists(collName, errCode);
361         if (errCode != E_OK) {
362             return errCode;
363         }
364         if (!isExists) {
365             GLOGE("[sqlite executor] Drop collection failed, collection not exists.");
366             return -E_INVALID_ARGS;
367         }
368     }
369 
370     std::string sql = "DROP TABLE IF EXISTS '" + collName + "';";
371     int errCode = RDSQLiteUtils::ExecSql(dbHandle_, sql);
372     if (errCode != E_OK) {
373         GLOGE("[sqlite executor] Drop collection failed. err=%d", errCode);
374     }
375     return errCode;
376 }
377 
IsCollectionExists(const std::string & name,int & errCode)378 bool SqliteStoreExecutorImpl::IsCollectionExists(const std::string &name, int &errCode)
379 {
380     bool isExists = false;
381     std::string sql = "SELECT tbl_name FROM sqlite_master WHERE tbl_name=?;";
382     errCode = RDSQLiteUtils::ExecSql(
383         dbHandle_, sql,
384         [name](sqlite3_stmt *stmt) {
385             RDSQLiteUtils::BindTextToStatement(stmt, 1, name);
386             return E_OK;
387         },
388         [&isExists](sqlite3_stmt *stmt, bool &isMatchOneData) {
389             isExists = true;
390             return E_OK;
391         });
392     if (errCode != E_OK) {
393         GLOGE("Check collection exist failed. %d", errCode);
394     }
395     return isExists;
396 }
397 
SetCollectionOption(const std::string & name,const std::string & option)398 int SqliteStoreExecutorImpl::SetCollectionOption(const std::string &name, const std::string &option)
399 {
400     std::string collOptKeyStr = "COLLECTION_OPTION_" + name;
401     Key collOptKey = { collOptKeyStr.begin(), collOptKeyStr.end() };
402     Value collOptVal = { option.begin(), option.end() };
403     return PutData("grd_meta", collOptKey, collOptVal, false); // dont need to add key type;
404 }
405 
CleanCollectionOption(const std::string & name)406 int SqliteStoreExecutorImpl::CleanCollectionOption(const std::string &name)
407 {
408     std::string collOptKeyStr = "COLLECTION_OPTION_" + name;
409     Key collOptKey = { collOptKeyStr.begin(), collOptKeyStr.end() };
410     return DelData("grd_meta", collOptKey);
411 }
412 } // namespace DocumentDB