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_ ? GetOnChangeType() : "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 " + GetOnChangeType() + " 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() && isTriggerObserver_) {
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() && isTriggerObserver_) {
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() && isTriggerObserver_) {
281 sql += "SELECT server_observer('" + tableName_ + "', 1);";
282 }
283 sql += "\nEND;";
284 return sql;
285 }
286
GetTempUpdateLogCursorTriggerSql() const287 const std::string TrackerTable::GetTempUpdateLogCursorTriggerSql() const
288 {
289 std::string sql = "CREATE TEMP TRIGGER IF NOT EXISTS " + std::string(DBConstant::RELATIONAL_PREFIX) + tableName_;
290 sql += "LOG_ON_UPDATE_TEMP AFTER UPDATE ON " + DBCommon::GetLogTableName(tableName_);
291 sql += " WHEN (SELECT 1 FROM " + std::string(DBConstant::RELATIONAL_PREFIX) + "metadata" +
292 " WHERE key = 'log_trigger_switch' AND value = 'false')\n";
293 sql += "BEGIN\n";
294 sql += CloudStorageUtils::GetCursorIncSql(tableName_) + "\n";
295 sql += "UPDATE " + DBCommon::GetLogTableName(tableName_) + " SET ";
296 sql += "cursor=" + CloudStorageUtils::GetSelectIncCursorSql(tableName_) + " WHERE data_key = OLD.data_key;\n";
297 sql += "END;";
298 return sql;
299 }
300
SetTableName(const std::string & tableName)301 void TrackerTable::SetTableName(const std::string &tableName)
302 {
303 tableName_ = tableName;
304 }
305
SetExtendNames(const std::set<std::string> & colNames)306 void TrackerTable::SetExtendNames(const std::set<std::string> &colNames)
307 {
308 extendColNames_ = std::move(colNames);
309 }
310
SetExtendName(const std::string & colName)311 void TrackerTable::SetExtendName(const std::string &colName)
312 {
313 extendColName_ = std::move(colName);
314 }
315
SetTrackerNames(const std::set<std::string> & trackerNames)316 void TrackerTable::SetTrackerNames(const std::set<std::string> &trackerNames)
317 {
318 trackerColNames_ = std::move(trackerNames);
319 }
320
IsEmpty() const321 bool TrackerTable::IsEmpty() const
322 {
323 return trackerColNames_.empty() && !isTrackerAction_;
324 }
325
IsTableNameEmpty() const326 bool TrackerTable::IsTableNameEmpty() const
327 {
328 return tableName_.empty();
329 }
330
IsChanging(const TrackerSchema & schema)331 bool TrackerTable::IsChanging(const TrackerSchema &schema)
332 {
333 if (tableName_ != schema.tableName || extendColNames_.size() != schema.extendColNames.size() ||
334 trackerColNames_.size() != schema.trackerColNames.size()) {
335 return true;
336 }
337 if (!extendColName_.empty()) {
338 return true;
339 }
340 for (const auto &col: extendColNames_) {
341 if (schema.extendColNames.find(col) == schema.extendColNames.end()) {
342 return true;
343 }
344 }
345 for (const auto &col: trackerColNames_) {
346 if (schema.trackerColNames.find(col) == schema.trackerColNames.end()) {
347 return true;
348 }
349 }
350 return isTrackerAction_ != schema.isTrackAction;
351 }
352
ReBuildTempTrigger(sqlite3 * db,TriggerMode::TriggerModeEnum mode,const AfterBuildAction & action)353 int TrackerTable::ReBuildTempTrigger(sqlite3 *db, TriggerMode::TriggerModeEnum mode, const AfterBuildAction &action)
354 {
355 sqlite3_stmt *stmt = nullptr;
356 int errCode = SQLiteUtils::GetStatement(db, "SELECT 1 FROM sqlite_temp_master where name='" +
357 GetTempTriggerName(mode) + "' and type='trigger' COLLATE NOCASE;", stmt);
358 if (errCode != E_OK) {
359 LOGE("Failed to select temp trigger mode:%d err:%d", mode, errCode);
360 return errCode;
361 }
362 errCode = SQLiteUtils::StepWithRetry(stmt);
363 bool isExists = (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) ? true : false;
364 int ret = E_OK;
365 SQLiteUtils::ResetStatement(stmt, true, ret);
366 if (errCode != SQLiteUtils::MapSQLiteErrno(SQLITE_ROW) && errCode != SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) {
367 LOGE("Select temp trigger step mode:%d err:%d", mode, errCode);
368 return errCode;
369 }
370 errCode = SQLiteUtils::ExecuteRawSQL(db, GetDropTempTriggerSql(mode));
371 if (errCode != E_OK) {
372 LOGE("Failed to drop temp trigger mode:%d err:%d", mode, errCode);
373 return errCode;
374 }
375 errCode = SQLiteUtils::ExecuteRawSQL(db, GetCreateTempTriggerSql(mode));
376 if (errCode != E_OK) {
377 LOGE("Failed to create temp trigger mode:%d err:%d", mode, errCode);
378 return errCode;
379 }
380 if (action != nullptr) {
381 errCode = action();
382 if (errCode != E_OK) {
383 return errCode;
384 }
385 }
386 if (!isExists) {
387 errCode = SQLiteUtils::ExecuteRawSQL(db, GetDropTempTriggerSql(mode));
388 if (errCode != E_OK) {
389 LOGE("Failed to clear temp trigger mode:%d err:%d", mode, errCode);
390 }
391 }
392 return errCode;
393 }
394
SetTrackerAction(bool isTrackerAction)395 void TrackerTable::SetTrackerAction(bool isTrackerAction)
396 {
397 isTrackerAction_ = isTrackerAction;
398 }
399
SetTriggerObserver(bool isTriggerObserver)400 void TrackerTable::SetTriggerObserver(bool isTriggerObserver)
401 {
402 isTriggerObserver_ = isTriggerObserver;
403 }
404
SetKnowledgeTable(bool isKnowledgeTable)405 void TrackerTable::SetKnowledgeTable(bool isKnowledgeTable)
406 {
407 isKnowledgeTable_ = isKnowledgeTable;
408 }
409
GetOnChangeType() const410 std::string TrackerTable::GetOnChangeType() const
411 {
412 return isKnowledgeTable_ ? std::to_string(CloudDbConstant::ON_CHANGE_KNOWLEDGE) :
413 std::to_string(CloudDbConstant::ON_CHANGE_TRACKER);
414 }
415 }
416 #endif
417