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 #ifdef RELATIONAL_STORE
16 #include "cloud/cloud_storage_utils.h"
17 #include "db_common.h"
18 #include "tracker_table.h"
19 #include "schema_constant.h"
20
21 namespace DistributedDB {
Init(const TrackerSchema & schema)22 void TrackerTable::Init(const TrackerSchema &schema)
23 {
24 tableName_ = schema.tableName;
25 extendColNames_ = schema.extendColNames;
26 trackerColNames_ = schema.trackerColNames;
27 isTrackerAction_ = schema.isTrackAction;
28 }
29
GetTableName() const30 std::string TrackerTable::GetTableName() const
31 {
32 return tableName_;
33 }
34
GetTrackerColNames() const35 const std::set<std::string> &TrackerTable::GetTrackerColNames() const
36 {
37 return trackerColNames_;
38 }
39
IsInvalidExtendColNames(const std::set<std::string> & extendColNames)40 bool IsInvalidExtendColNames(const std::set<std::string> &extendColNames)
41 {
42 for (auto &extendColName : extendColNames) {
43 if (extendColName.empty()) {
44 return true;
45 }
46 }
47 return false;
48 }
49
GetJsonAssignValSql(bool isDelete,const std::set<std::string> & extendColNames)50 const std::string GetJsonAssignValSql(bool isDelete, const std::set<std::string> &extendColNames)
51 {
52 if (extendColNames.empty()) {
53 return "''";
54 }
55 std::string newOrOld = isDelete ? "OLD." : "NEW.";
56 std::string sql = "json_object(";
57 for (auto &extendColName : extendColNames) {
58 sql += "'" + extendColName + "'," + newOrOld + extendColName + ",";
59 }
60 sql.pop_back();
61 sql += ")";
62 return sql;
63 }
64
GetAssignValSql(bool isDelete) const65 const std::string TrackerTable::GetAssignValSql(bool isDelete) const
66 {
67 if (!extendColNames_.empty() && !IsInvalidExtendColNames(extendColNames_)) {
68 return GetJsonAssignValSql(isDelete, extendColNames_);
69 }
70 return "''";
71 }
72
GetExtendAssignValSql(bool isDelete) const73 const std::string TrackerTable::GetExtendAssignValSql(bool isDelete) const
74 {
75 if (!extendColNames_.empty() && !IsInvalidExtendColNames(extendColNames_)) {
76 return ", extend_field = " + GetJsonAssignValSql(isDelete, extendColNames_);
77 }
78 return "";
79 }
80
GetDiffTrackerValSql() const81 const std::string TrackerTable::GetDiffTrackerValSql() const
82 {
83 if (trackerColNames_.empty() || isTrackerAction_) {
84 return isTrackerAction_ ? "1" : "0";
85 }
86 std::string sql = " CASE WHEN (";
87 size_t index = 0;
88 for (const auto &colName: trackerColNames_) {
89 sql += "(NEW." + colName + " IS NOT OLD." + colName + ")";
90 if (index < trackerColNames_.size() - 1) {
91 sql += " OR ";
92 }
93 index++;
94 }
95 sql += ") THEN 1 ELSE 0 END";
96 return sql;
97 }
98
GetDiffIncCursorSql(const std::string & tableName) const99 const std::string TrackerTable::GetDiffIncCursorSql(const std::string &tableName) const
100 {
101 if (IsEmpty()) {
102 return "";
103 }
104 if (isTrackerAction_) {
105 return std::string(", cursor = ").append(CloudStorageUtils::GetSelectIncCursorSql(tableName)).append(" ");
106 }
107 std::string sql = ", cursor = CASE WHEN (";
108 size_t index = 0;
109 for (const auto &colName: trackerColNames_) {
110 sql += "(NEW." + colName + " IS NOT OLD." + colName + ")";
111 if (index < trackerColNames_.size() - 1) {
112 sql += " OR ";
113 }
114 index++;
115 }
116 sql += ") THEN " + CloudStorageUtils::GetSelectIncCursorSql(tableName);
117 sql += " ELSE cursor END ";
118 return sql;
119 }
120
GetExtendNames() const121 const std::set<std::string> &TrackerTable::GetExtendNames() const
122 {
123 return extendColNames_;
124 }
125
GetExtendName() const126 const std::string TrackerTable::GetExtendName() const
127 {
128 return extendColName_;
129 }
130
ToString() const131 std::string TrackerTable::ToString() const
132 {
133 std::string attrStr;
134 attrStr += "{";
135 attrStr += R"("NAME": ")" + tableName_ + "\",";
136 attrStr += R"("EXTEND_NAMES": [)";
137 for (const auto &colName : extendColNames_) {
138 attrStr += "\"" + colName + "\",";
139 }
140 if (!extendColNames_.empty()) {
141 attrStr.pop_back();
142 }
143 attrStr += "],";
144 attrStr += R"("TRACKER_NAMES": [)";
145 for (const auto &colName: trackerColNames_) {
146 attrStr += "\"" + colName + "\",";
147 }
148 if (!trackerColNames_.empty()) {
149 attrStr.pop_back();
150 }
151 attrStr += "],";
152 attrStr += R"("TRACKER_ACTION": )";
153 attrStr += isTrackerAction_ ? SchemaConstant::KEYWORD_ATTR_VALUE_TRUE : SchemaConstant::KEYWORD_ATTR_VALUE_FALSE;
154 attrStr += "}";
155 return attrStr;
156 }
157
GetDropTempTriggerSql() const158 const std::vector<std::string> TrackerTable::GetDropTempTriggerSql() const
159 {
160 if (IsEmpty()) {
161 return {};
162 }
163 std::vector<std::string> dropSql;
164 dropSql.push_back(GetDropTempTriggerSql(TriggerMode::TriggerModeEnum::INSERT));
165 dropSql.push_back(GetDropTempTriggerSql(TriggerMode::TriggerModeEnum::UPDATE));
166 dropSql.push_back(GetDropTempTriggerSql(TriggerMode::TriggerModeEnum::DELETE));
167 return dropSql;
168 }
169
GetDropTempTriggerSql(TriggerMode::TriggerModeEnum mode) const170 const std::string TrackerTable::GetDropTempTriggerSql(TriggerMode::TriggerModeEnum mode) const
171 {
172 return "DROP TRIGGER IF EXISTS " + GetTempTriggerName(mode);
173 }
174
GetCreateTempTriggerSql(TriggerMode::TriggerModeEnum mode) const175 const std::string TrackerTable::GetCreateTempTriggerSql(TriggerMode::TriggerModeEnum mode) const
176 {
177 switch (mode) {
178 case TriggerMode::TriggerModeEnum::INSERT:
179 return GetTempInsertTriggerSql();
180 case TriggerMode::TriggerModeEnum::UPDATE:
181 return GetTempUpdateTriggerSql();
182 case TriggerMode::TriggerModeEnum::DELETE:
183 return GetTempDeleteTriggerSql();
184 default:
185 return {};
186 }
187 }
188
GetTempTriggerName(TriggerMode::TriggerModeEnum mode) const189 const std::string TrackerTable::GetTempTriggerName(TriggerMode::TriggerModeEnum mode) const
190 {
191 return DBConstant::RELATIONAL_PREFIX + tableName_ + "_ON_" + TriggerMode::GetTriggerModeString(mode) + "_TEMP";
192 }
193
GetTempInsertTriggerSql(bool incFlag) const194 const std::string TrackerTable::GetTempInsertTriggerSql(bool incFlag) const
195 {
196 // This trigger is built on the log table
197 std::string sql = "CREATE TEMP TRIGGER IF NOT EXISTS " + std::string(DBConstant::RELATIONAL_PREFIX) + tableName_;
198 sql += "_ON_INSERT_TEMP AFTER INSERT ON " + std::string(DBConstant::RELATIONAL_PREFIX) + tableName_ + "_log";
199 sql += " WHEN (SELECT 1 FROM " + std::string(DBConstant::RELATIONAL_PREFIX) + "metadata" +
200 " WHERE key = 'log_trigger_switch' AND value = 'false')\n";
201 sql += "BEGIN\n";
202 if (incFlag) {
203 sql += CloudStorageUtils::GetCursorIncSqlWhenAllow(tableName_) + "\n";
204 } else {
205 sql += CloudStorageUtils::GetCursorIncSql(tableName_) + "\n";
206 }
207 sql += "UPDATE " + std::string(DBConstant::RELATIONAL_PREFIX) + tableName_ + "_log" + " SET ";
208 if (incFlag) {
209 sql += "cursor= case when (select 1 from " + std::string(DBConstant::RELATIONAL_PREFIX) +
210 "metadata where key='cursor_inc_flag' AND value = 'true') then " +
211 CloudStorageUtils::GetSelectIncCursorSql(tableName_) + " else cursor end WHERE";
212 } else {
213 sql += "cursor=" + CloudStorageUtils::GetSelectIncCursorSql(tableName_) + " WHERE";
214 }
215 sql += " hash_key = NEW.hash_key;\n";
216 if (!IsEmpty()) {
217 sql += "SELECT server_observer('" + tableName_ + "', 1);";
218 }
219 sql += "\nEND;";
220 return sql;
221 }
222
GetTempUpdateTriggerSql(bool incFlag) const223 const std::string TrackerTable::GetTempUpdateTriggerSql(bool incFlag) const
224 {
225 std::string sql = "CREATE TEMP TRIGGER IF NOT EXISTS " + std::string(DBConstant::RELATIONAL_PREFIX) + tableName_;
226 sql += "_ON_UPDATE_TEMP AFTER UPDATE ON " + tableName_;
227 sql += " WHEN (SELECT 1 FROM " + std::string(DBConstant::RELATIONAL_PREFIX) + "metadata" +
228 " WHERE key = 'log_trigger_switch' AND value = 'false')\n";
229 sql += "BEGIN\n";
230 if (incFlag) {
231 sql += CloudStorageUtils::GetCursorIncSqlWhenAllow(tableName_) + "\n";
232 } else {
233 sql += CloudStorageUtils::GetCursorIncSql(tableName_) + "\n";
234 }
235 sql += "UPDATE " + std::string(DBConstant::RELATIONAL_PREFIX) + tableName_ + "_log" + " SET ";
236 if (!IsEmpty()) {
237 sql += "extend_field=" + GetAssignValSql() + ",";
238 }
239 if (incFlag) {
240 sql += "cursor= case when (select 1 from " + std::string(DBConstant::RELATIONAL_PREFIX) +
241 "metadata where key='cursor_inc_flag' AND value = 'true') then " +
242 CloudStorageUtils::GetSelectIncCursorSql(tableName_) + " else cursor end WHERE";
243 } else {
244 sql += "cursor=" + CloudStorageUtils::GetSelectIncCursorSql(tableName_) + " WHERE";
245 }
246 sql += " data_key = OLD." + std::string(DBConstant::SQLITE_INNER_ROWID) + ";\n";
247 if (!IsEmpty()) {
248 sql += "SELECT server_observer('" + tableName_ + "', " + GetDiffTrackerValSql() + ");";
249 }
250 sql += "\nEND;";
251 return sql;
252 }
253
GetTempDeleteTriggerSql(bool incFlag) const254 const std::string TrackerTable::GetTempDeleteTriggerSql(bool incFlag) const
255 {
256 std::string sql = "CREATE TEMP TRIGGER IF NOT EXISTS " + std::string(DBConstant::RELATIONAL_PREFIX) + tableName_;
257 sql += "_ON_DELETE_TEMP AFTER DELETE ON " + tableName_ +
258 " WHEN (SELECT 1 FROM " + std::string(DBConstant::RELATIONAL_PREFIX) + "metadata" +
259 " WHERE key = 'log_trigger_switch' AND value = 'false')\n";
260 sql += "BEGIN\n";
261 if (IsEmpty() && incFlag) {
262 sql += "SELECT 1;\n";
263 sql += "\nEND;";
264 return sql;
265 }
266 if (!incFlag) {
267 sql += CloudStorageUtils::GetCursorIncSql(tableName_) + "\n";
268 }
269 sql += "UPDATE " + std::string(DBConstant::RELATIONAL_PREFIX) + tableName_ + "_log" + " SET ";
270 if (!IsEmpty()) {
271 sql += "extend_field=" + GetAssignValSql(true) + ",";
272 }
273 if (!incFlag) {
274 sql += "cursor=" + CloudStorageUtils::GetSelectIncCursorSql(tableName_);
275 }
276 if (!IsEmpty() && incFlag) {
277 sql.pop_back();
278 }
279 sql += " WHERE data_key = OLD." + std::string(DBConstant::SQLITE_INNER_ROWID) + ";\n";
280 if (!IsEmpty()) {
281 sql += "SELECT server_observer('" + tableName_ + "', 1);";
282 }
283 sql += "\nEND;";
284 return sql;
285 }
286
SetTableName(const std::string & tableName)287 void TrackerTable::SetTableName(const std::string &tableName)
288 {
289 tableName_ = tableName;
290 }
291
SetExtendNames(const std::set<std::string> & colNames)292 void TrackerTable::SetExtendNames(const std::set<std::string> &colNames)
293 {
294 extendColNames_ = std::move(colNames);
295 }
296
SetExtendName(const std::string & colName)297 void TrackerTable::SetExtendName(const std::string &colName)
298 {
299 extendColName_ = std::move(colName);
300 }
301
SetTrackerNames(const std::set<std::string> & trackerNames)302 void TrackerTable::SetTrackerNames(const std::set<std::string> &trackerNames)
303 {
304 trackerColNames_ = std::move(trackerNames);
305 }
306
IsEmpty() const307 bool TrackerTable::IsEmpty() const
308 {
309 return trackerColNames_.empty() && !isTrackerAction_;
310 }
311
IsTableNameEmpty() const312 bool TrackerTable::IsTableNameEmpty() const
313 {
314 return tableName_.empty();
315 }
316
IsChanging(const TrackerSchema & schema)317 bool TrackerTable::IsChanging(const TrackerSchema &schema)
318 {
319 if (tableName_ != schema.tableName || extendColNames_.size() != schema.extendColNames.size() ||
320 trackerColNames_.size() != schema.trackerColNames.size()) {
321 return true;
322 }
323 if (!extendColName_.empty()) {
324 return true;
325 }
326 for (const auto &col: extendColNames_) {
327 if (schema.extendColNames.find(col) == schema.extendColNames.end()) {
328 return true;
329 }
330 }
331 for (const auto &col: trackerColNames_) {
332 if (schema.trackerColNames.find(col) == schema.trackerColNames.end()) {
333 return true;
334 }
335 }
336 return isTrackerAction_ != schema.isTrackAction;
337 }
338
ReBuildTempTrigger(sqlite3 * db,TriggerMode::TriggerModeEnum mode,const AfterBuildAction & action)339 int TrackerTable::ReBuildTempTrigger(sqlite3 *db, TriggerMode::TriggerModeEnum mode, const AfterBuildAction &action)
340 {
341 sqlite3_stmt *stmt = nullptr;
342 int errCode = SQLiteUtils::GetStatement(db, "SELECT 1 FROM sqlite_temp_master where name='" +
343 GetTempTriggerName(mode) + "' and type='trigger' COLLATE NOCASE;", stmt);
344 if (errCode != E_OK) {
345 LOGE("Failed to select temp trigger mode:%d err:%d", mode, errCode);
346 return errCode;
347 }
348 errCode = SQLiteUtils::StepWithRetry(stmt);
349 bool isExists = (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) ? true : false;
350 int ret = E_OK;
351 SQLiteUtils::ResetStatement(stmt, true, ret);
352 if (errCode != SQLiteUtils::MapSQLiteErrno(SQLITE_ROW) && errCode != SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) {
353 LOGE("Select temp trigger step mode:%d err:%d", mode, errCode);
354 return errCode;
355 }
356 errCode = SQLiteUtils::ExecuteRawSQL(db, GetDropTempTriggerSql(mode));
357 if (errCode != E_OK) {
358 LOGE("Failed to drop temp trigger mode:%d err:%d", mode, errCode);
359 return errCode;
360 }
361 errCode = SQLiteUtils::ExecuteRawSQL(db, GetCreateTempTriggerSql(mode));
362 if (errCode != E_OK) {
363 LOGE("Failed to create temp trigger mode:%d err:%d", mode, errCode);
364 return errCode;
365 }
366 if (action != nullptr) {
367 errCode = action();
368 if (errCode != E_OK) {
369 return errCode;
370 }
371 }
372 if (!isExists) {
373 errCode = SQLiteUtils::ExecuteRawSQL(db, GetDropTempTriggerSql(mode));
374 if (errCode != E_OK) {
375 LOGE("Failed to clear temp trigger mode:%d err:%d", mode, errCode);
376 }
377 }
378 return errCode;
379 }
380
SetTrackerAction(bool isTrackerAction)381 void TrackerTable::SetTrackerAction(bool isTrackerAction)
382 {
383 isTrackerAction_ = isTrackerAction;
384 }
385 }
386 #endif
387