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 "relational_sync_data_inserter.h"
17 #include "data_transformer.h"
18 #include "db_common.h"
19 #include "sqlite_utils.h"
20 
21 namespace DistributedDB {
ResetStatements(bool isNeedFinalize)22 int SaveSyncDataStmt::ResetStatements(bool isNeedFinalize)
23 {
24     int errCode = E_OK;
25     if (saveDataStmt != nullptr) {
26         SQLiteUtils::ResetStatement(saveDataStmt, isNeedFinalize, errCode);
27     }
28     if (saveLogStmt != nullptr) {
29         SQLiteUtils::ResetStatement(saveLogStmt, isNeedFinalize, errCode);
30     }
31     if (queryStmt != nullptr) {
32         SQLiteUtils::ResetStatement(queryStmt, isNeedFinalize, errCode);
33     }
34     if (rmDataStmt != nullptr) {
35         SQLiteUtils::ResetStatement(rmDataStmt, isNeedFinalize, errCode);
36     }
37     if (rmLogStmt != nullptr) {
38         SQLiteUtils::ResetStatement(rmLogStmt, isNeedFinalize, errCode);
39     }
40     return errCode;
41 }
42 
RelationalSyncDataInserter()43 RelationalSyncDataInserter::RelationalSyncDataInserter()
44 {
45 }
46 
~RelationalSyncDataInserter()47 RelationalSyncDataInserter::~RelationalSyncDataInserter()
48 {
49 }
50 
CreateInserter(const std::string & deviceName,const QueryObject & query,const RelationalSchemaObject & localSchema,const std::vector<FieldInfo> & remoteFields,const StoreInfo & info)51 RelationalSyncDataInserter RelationalSyncDataInserter::CreateInserter(const std::string &deviceName,
52     const QueryObject &query, const RelationalSchemaObject &localSchema, const std::vector<FieldInfo> &remoteFields,
53     const StoreInfo &info)
54 {
55     RelationalSyncDataInserter inserter;
56     inserter.SetHashDevId(DBCommon::TransferStringToHex(DBCommon::TransferHashString(deviceName)));
57     inserter.SetRemoteFields(remoteFields);
58     inserter.SetQuery(query);
59     TableInfo localTable = localSchema.GetTable(query.GetTableName());
60     inserter.SetLocalTable(localTable);
61     inserter.SetTableMode(localSchema.GetTableMode());
62     if (localSchema.GetTableMode() == DistributedTableMode::COLLABORATION) {
63         inserter.SetInsertTableName(localTable.GetTableName());
64     } else {
65         inserter.SetInsertTableName(DBCommon::GetDistributedTableName(deviceName, localTable.GetTableName(), info));
66     }
67     return inserter;
68 }
69 
SetHashDevId(const std::string & hashDevId)70 void RelationalSyncDataInserter::SetHashDevId(const std::string &hashDevId)
71 {
72     hashDevId_ = hashDevId;
73 }
74 
SetRemoteFields(std::vector<FieldInfo> remoteFields)75 void RelationalSyncDataInserter::SetRemoteFields(std::vector<FieldInfo> remoteFields)
76 {
77     remoteFields_ = std::move(remoteFields);
78 }
79 
SetEntries(std::vector<DataItem> entries)80 void RelationalSyncDataInserter::SetEntries(std::vector<DataItem> entries)
81 {
82     entries_ = std::move(entries);
83 }
84 
SetLocalTable(TableInfo localTable)85 void RelationalSyncDataInserter::SetLocalTable(TableInfo localTable)
86 {
87     localTable_ = std::move(localTable);
88 }
89 
GetLocalTable() const90 const TableInfo &RelationalSyncDataInserter::GetLocalTable() const
91 {
92     return localTable_;
93 }
94 
SetQuery(QueryObject query)95 void RelationalSyncDataInserter::SetQuery(QueryObject query)
96 {
97     query_ = std::move(query);
98 }
99 
SetInsertTableName(std::string tableName)100 void RelationalSyncDataInserter::SetInsertTableName(std::string tableName)
101 {
102     insertTableName_ = std::move(tableName);
103 }
104 
SetTableMode(DistributedTableMode mode)105 void RelationalSyncDataInserter::SetTableMode(DistributedTableMode mode)
106 {
107     mode_ = mode;
108 }
109 
GetInsertStatement(sqlite3 * db,sqlite3_stmt * & stmt)110 int RelationalSyncDataInserter::GetInsertStatement(sqlite3 *db, sqlite3_stmt *&stmt)
111 {
112     if (stmt != nullptr) {
113         return -E_INVALID_ARGS;
114     }
115 
116     const auto &localTableFields = localTable_.GetFields();
117     std::string colName;
118     std::string dataFormat;
119     for (const auto &it : remoteFields_) {
120         if (localTableFields.find(it.GetFieldName()) == localTableFields.end()) {
121             continue; // skip fields which is orphaned in remote
122         }
123         colName += "'" + it.GetFieldName() + "',";
124         dataFormat += "?,";
125     }
126     colName.pop_back();
127     dataFormat.pop_back();
128 
129     const std::string sql = "INSERT OR REPLACE INTO '" + insertTableName_ + "'" +
130         " (" + colName + ") VALUES (" + dataFormat + ");";
131     int errCode = SQLiteUtils::GetStatement(db, sql, stmt);
132     if (errCode != E_OK) {
133         LOGE("Get saving data statement fail! errCode:%d", errCode);
134     }
135     return errCode;
136 }
137 
BindInsertStatement(sqlite3_stmt * stmt,const DataItem & dataItem)138 int RelationalSyncDataInserter::BindInsertStatement(sqlite3_stmt *stmt, const DataItem &dataItem)
139 {
140     if (stmt == nullptr) {
141         return -E_INVALID_ARGS;
142     }
143 
144     OptRowDataWithLog data;
145     // deserialize by remote field info
146     int errCode = DataTransformer::DeSerializeDataItem(dataItem, data, remoteFields_);
147     if (errCode != E_OK) {
148         LOGE("DeSerialize dataItem failed! errCode = [%d]", errCode);
149         return errCode;
150     }
151 
152     size_t dataIdx = 0;
153     int bindIdx = 1;
154     const auto &localTableFields = localTable_.GetFields();
155     for (const auto &it : remoteFields_) {
156         if (localTableFields.find(it.GetFieldName()) == localTableFields.end()) {
157             LOGD("field %s not found in local schema.", it.GetFieldName().c_str());
158             dataIdx++;
159             continue; // skip fields which is orphaned in remote
160         }
161         if (dataIdx >= data.optionalData.size()) {
162             LOGD("field over size. cnt:%d, data size:%d", dataIdx, data.optionalData.size());
163             break; // cnt should less then optionalData size.
164         }
165         errCode = SQLiteUtils::BindDataValueByType(stmt, data.optionalData[dataIdx], bindIdx++);
166         if (errCode != E_OK) {
167             LOGE("Bind data failed, errCode:%d, cid:%zu.", errCode, dataIdx);
168             return errCode;
169         }
170         dataIdx++;
171     }
172 
173     return E_OK;
174 }
175 
GetDeleteLogStmt(sqlite3 * db,sqlite3_stmt * & stmt)176 int RelationalSyncDataInserter::GetDeleteLogStmt(sqlite3 *db, sqlite3_stmt *&stmt)
177 {
178     std::string sql = "DELETE FROM " + DBConstant::RELATIONAL_PREFIX + localTable_.GetTableName() + "_log ";
179     if (mode_ == DistributedTableMode::COLLABORATION) {
180         sql += "WHERE hash_key=?";
181     } else {
182         sql += "WHERE hash_key=? AND device=?";
183     }
184 
185     int errCode = SQLiteUtils::GetStatement(db, sql, stmt);
186     if (errCode != E_OK) {
187         LOGE("[DeleteSyncLog] Get statement fail!");
188     }
189     return errCode;
190 }
191 
GetDeleteSyncDataStmt(sqlite3 * db,sqlite3_stmt * & stmt)192 int RelationalSyncDataInserter::GetDeleteSyncDataStmt(sqlite3 *db, sqlite3_stmt *&stmt)
193 {
194     std::string sql = "DELETE FROM '" + insertTableName_ + "' WHERE " + std::string(DBConstant::SQLITE_INNER_ROWID) +
195         " IN (SELECT data_key FROM " + DBConstant::RELATIONAL_PREFIX + localTable_.GetTableName() + "_log ";
196     if (mode_ == DistributedTableMode::COLLABORATION) {
197         sql += "WHERE hash_key=?);";
198     } else {
199         sql += "WHERE hash_key=? AND device=? AND flag&0x01=0);";
200     }
201     int errCode = SQLiteUtils::GetStatement(db, sql, stmt);
202     if (errCode != E_OK) {
203         LOGE("[DeleteSyncDataItem] Get statement fail!, errCode:%d", errCode);
204     }
205     return errCode;
206 }
207 
GetSaveLogStatement(sqlite3 * db,sqlite3_stmt * & logStmt,sqlite3_stmt * & queryStmt)208 int RelationalSyncDataInserter::GetSaveLogStatement(sqlite3 *db, sqlite3_stmt *&logStmt, sqlite3_stmt *&queryStmt)
209 {
210     const std::string tableName = DBConstant::RELATIONAL_PREFIX + query_.GetTableName() + "_log";
211     std::string dataFormat = "?, '" + hashDevId_ + "', ?, ?, ?, ?, ?";
212     std::string columnList = "data_key, device, ori_device, timestamp, wtimestamp, flag, hash_key";
213     std::string sql = "INSERT OR REPLACE INTO " + tableName +
214         " (" + columnList + ") VALUES (" + dataFormat + ");";
215     int errCode = SQLiteUtils::GetStatement(db, sql, logStmt);
216     if (errCode != E_OK) {
217         LOGE("[info statement] Get log statement fail! errCode:%d", errCode);
218         return errCode;
219     }
220     std::string selectSql = "select " + columnList + " from " + tableName;
221     if (mode_ == DistributedTableMode::COLLABORATION) {
222         selectSql += " where hash_key = ?;";
223     } else {
224         selectSql += " where hash_key = ? and device = ?;";
225     }
226     errCode = SQLiteUtils::GetStatement(db, selectSql, queryStmt);
227     if (errCode != E_OK) {
228         SQLiteUtils::ResetStatement(logStmt, true, errCode);
229         LOGE("[info statement] Get query statement fail! errCode:%d", errCode);
230     }
231     return errCode;
232 }
233 
PrepareStatement(sqlite3 * db,SaveSyncDataStmt & stmt)234 int RelationalSyncDataInserter::PrepareStatement(sqlite3 *db, SaveSyncDataStmt &stmt)
235 {
236     int errCode = GetSaveLogStatement(db, stmt.saveLogStmt, stmt.queryStmt);
237     if (errCode != E_OK) {
238         LOGE("Get save log statement failed. err=%d", errCode);
239         return errCode;
240     }
241     errCode = GetInsertStatement(db, stmt.saveDataStmt);
242     if (errCode != E_OK) {
243         LOGE("Get insert statement failed. err=%d", errCode);
244     }
245     return errCode;
246 }
247 
Iterate(const std::function<int (DataItem &)> & saveSyncDataItem)248 int RelationalSyncDataInserter::Iterate(const std::function<int (DataItem &)> &saveSyncDataItem)
249 {
250     int errCode = E_OK;
251     for (auto &it : entries_) {
252         it.dev = hashDevId_;
253         errCode = saveSyncDataItem(it);
254         if (errCode != E_OK) {
255             LOGE("Save sync data item failed. err=%d", errCode);
256             break;
257         }
258     }
259     return errCode;
260 }
261 } // namespace DistributedDB