• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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