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 extendColName_ = schema.extendColName;
26 trackerColNames_ = schema.trackerColNames;
27 }
28
GetTableName() const29 std::string TrackerTable::GetTableName() const
30 {
31 return tableName_;
32 }
33
GetTrackerColNames() const34 const std::set<std::string> &TrackerTable::GetTrackerColNames() const
35 {
36 return trackerColNames_;
37 }
38
GetAssignValSql(bool isDelete) const39 const std::string TrackerTable::GetAssignValSql(bool isDelete) const
40 {
41 if (extendColName_.empty()) {
42 return "''";
43 }
44 return isDelete ? ("OLD." + extendColName_) : ("NEW." + extendColName_);
45 }
46
GetExtendAssignValSql(bool isDelete) const47 const std::string TrackerTable::GetExtendAssignValSql(bool isDelete) const
48 {
49 if (extendColName_.empty()) {
50 return "";
51 }
52 return isDelete ? (", extend_field = OLD." + extendColName_) : (", extend_field = NEW." + extendColName_);
53 }
54
GetDiffTrackerValSql() const55 const std::string TrackerTable::GetDiffTrackerValSql() const
56 {
57 if (trackerColNames_.empty()) {
58 return "0";
59 }
60 std::string sql = " CASE WHEN (";
61 size_t index = 0;
62 for (const auto &colName: trackerColNames_) {
63 sql += "(NEW." + colName + " IS NOT OLD." + colName + ")";
64 if (index < trackerColNames_.size() - 1) {
65 sql += " OR ";
66 }
67 index++;
68 }
69 sql += ") THEN 1 ELSE 0 END";
70 return sql;
71 }
72
GetDiffIncCursorSql(const std::string & tableName) const73 const std::string TrackerTable::GetDiffIncCursorSql(const std::string &tableName) const
74 {
75 if (trackerColNames_.empty()) {
76 return "";
77 }
78 std::string sql = ", cursor = CASE WHEN (";
79 size_t index = 0;
80 for (const auto &colName: trackerColNames_) {
81 sql += "(NEW." + colName + " IS NOT OLD." + colName + ")";
82 if (index < trackerColNames_.size() - 1) {
83 sql += " OR ";
84 }
85 index++;
86 }
87 sql += ") THEN " + CloudStorageUtils::GetSelectIncCursorSql(tableName);
88 sql += " ELSE cursor END ";
89 return sql;
90 }
91
GetExtendName() const92 const std::string TrackerTable::GetExtendName() const
93 {
94 return extendColName_;
95 }
96
ToString() const97 std::string TrackerTable::ToString() const
98 {
99 std::string attrStr;
100 attrStr += "{";
101 attrStr += R"("NAME": ")" + tableName_ + "\",";
102 attrStr += R"("EXTEND_NAME": ")" + extendColName_ + "\",";
103 attrStr += R"("TRACKER_NAMES": [)";
104 for (const auto &colName: trackerColNames_) {
105 attrStr += "\"" + colName + "\",";
106 }
107 attrStr.pop_back();
108 attrStr += "]}";
109 return attrStr;
110 }
111
GetDropTempTriggerSql() const112 const std::vector<std::string> TrackerTable::GetDropTempTriggerSql() const
113 {
114 if (IsEmpty()) {
115 return {};
116 }
117 std::vector<std::string> dropSql;
118 dropSql.push_back(GetDropTempTriggerSql(TriggerMode::TriggerModeEnum::INSERT));
119 dropSql.push_back(GetDropTempTriggerSql(TriggerMode::TriggerModeEnum::UPDATE));
120 dropSql.push_back(GetDropTempTriggerSql(TriggerMode::TriggerModeEnum::DELETE));
121 return dropSql;
122 }
123
GetDropTempTriggerSql(TriggerMode::TriggerModeEnum mode) const124 const std::string TrackerTable::GetDropTempTriggerSql(TriggerMode::TriggerModeEnum mode) const
125 {
126 return "DROP TRIGGER IF EXISTS " + GetTempTriggerName(mode);
127 }
128
GetCreateTempTriggerSql(TriggerMode::TriggerModeEnum mode) const129 const std::string TrackerTable::GetCreateTempTriggerSql(TriggerMode::TriggerModeEnum mode) const
130 {
131 switch (mode) {
132 case TriggerMode::TriggerModeEnum::INSERT:
133 return GetTempInsertTriggerSql();
134 case TriggerMode::TriggerModeEnum::UPDATE:
135 return GetTempUpdateTriggerSql();
136 case TriggerMode::TriggerModeEnum::DELETE:
137 return GetTempDeleteTriggerSql();
138 default:
139 return {};
140 }
141 }
142
GetTempTriggerName(TriggerMode::TriggerModeEnum mode) const143 const std::string TrackerTable::GetTempTriggerName(TriggerMode::TriggerModeEnum mode) const
144 {
145 return DBConstant::RELATIONAL_PREFIX + tableName_ + "_ON_" + TriggerMode::GetTriggerModeString(mode) + "_TEMP";
146 }
147
GetTempInsertTriggerSql(bool incFlag) const148 const std::string TrackerTable::GetTempInsertTriggerSql(bool incFlag) const
149 {
150 // This trigger is built on the log table
151 std::string sql = "CREATE TEMP TRIGGER IF NOT EXISTS " + DBConstant::RELATIONAL_PREFIX + tableName_;
152 sql += "_ON_INSERT_TEMP AFTER INSERT ON " + DBConstant::RELATIONAL_PREFIX + tableName_ + "_log";
153 sql += " WHEN (SELECT 1 FROM " + DBConstant::RELATIONAL_PREFIX + "metadata" +
154 " WHERE key = 'log_trigger_switch' AND value = 'false')\n";
155 sql += "BEGIN\n";
156 if (incFlag) {
157 sql += CloudStorageUtils::GetCursorIncSqlWhenAllow(tableName_) + "\n";
158 } else {
159 sql += CloudStorageUtils::GetCursorIncSql(tableName_) + "\n";
160 }
161 sql += "UPDATE " + DBConstant::RELATIONAL_PREFIX + tableName_ + "_log" + " SET ";
162 sql += "cursor=" + CloudStorageUtils::GetSelectIncCursorSql(tableName_) + " WHERE";
163 sql += " hash_key = NEW.hash_key;\n";
164 if (!IsEmpty()) {
165 sql += "SELECT server_observer('" + tableName_ + "', 1);";
166 }
167 sql += "\nEND;";
168 return sql;
169 }
170
GetTempUpdateTriggerSql(bool incFlag) const171 const std::string TrackerTable::GetTempUpdateTriggerSql(bool incFlag) const
172 {
173 std::string sql = "CREATE TEMP TRIGGER IF NOT EXISTS " + DBConstant::RELATIONAL_PREFIX + tableName_;
174 sql += "_ON_UPDATE_TEMP AFTER UPDATE ON " + tableName_;
175 sql += " WHEN (SELECT 1 FROM " + DBConstant::RELATIONAL_PREFIX + "metadata" +
176 " WHERE key = 'log_trigger_switch' AND value = 'false')\n";
177 sql += "BEGIN\n";
178 if (incFlag) {
179 sql += CloudStorageUtils::GetCursorIncSqlWhenAllow(tableName_) + "\n";
180 } else {
181 sql += CloudStorageUtils::GetCursorIncSql(tableName_) + "\n";
182 }
183 sql += "UPDATE " + DBConstant::RELATIONAL_PREFIX + tableName_ + "_log" + " SET ";
184 if (!IsEmpty()) {
185 sql += "extend_field=" + GetAssignValSql() + ",";
186 }
187 sql += "cursor=" + CloudStorageUtils::GetSelectIncCursorSql(tableName_) + " WHERE";
188 sql += " data_key = OLD." + std::string(DBConstant::SQLITE_INNER_ROWID) + ";\n";
189 if (!IsEmpty()) {
190 sql += "SELECT server_observer('" + tableName_ + "', " + GetDiffTrackerValSql() + ");";
191 }
192 sql += "\nEND;";
193 return sql;
194 }
195
GetTempDeleteTriggerSql(bool incFlag) const196 const std::string TrackerTable::GetTempDeleteTriggerSql(bool incFlag) const
197 {
198 std::string sql = "CREATE TEMP TRIGGER IF NOT EXISTS " + DBConstant::RELATIONAL_PREFIX + tableName_;
199 sql += "_ON_DELETE_TEMP AFTER DELETE ON " + tableName_ +
200 " WHEN (SELECT 1 FROM " + DBConstant::RELATIONAL_PREFIX + "metadata" +
201 " WHERE key = 'log_trigger_switch' AND value = 'false')\n";
202 sql += "BEGIN\n";
203 if (IsEmpty() && incFlag) {
204 sql += " SELECT 1;\n";
205 sql += "\nEND;";
206 return sql;
207 }
208 if (!incFlag) {
209 sql += CloudStorageUtils::GetCursorIncSql(tableName_) + "\n";
210 }
211 sql += "UPDATE " + DBConstant::RELATIONAL_PREFIX + tableName_ + "_log" + " SET ";
212 if (!IsEmpty()) {
213 sql += "extend_field=" + GetAssignValSql(true) + ",";
214 }
215 if (!incFlag) {
216 sql += "cursor=" + CloudStorageUtils::GetSelectIncCursorSql(tableName_);
217 }
218 if (!IsEmpty() && incFlag) {
219 sql.pop_back();
220 }
221 sql += " WHERE data_key = OLD." + std::string(DBConstant::SQLITE_INNER_ROWID) + ";\n";
222 if (!IsEmpty()) {
223 sql += "SELECT server_observer('" + tableName_ + "', 1);";
224 }
225 sql += "\nEND;";
226 return sql;
227 }
228
SetTableName(const std::string & tableName)229 void TrackerTable::SetTableName(const std::string &tableName)
230 {
231 tableName_ = tableName;
232 }
233
SetExtendName(const std::string & colName)234 void TrackerTable::SetExtendName(const std::string &colName)
235 {
236 extendColName_ = colName;
237 }
238
SetTrackerNames(const std::set<std::string> & trackerNames)239 void TrackerTable::SetTrackerNames(const std::set<std::string> &trackerNames)
240 {
241 trackerColNames_ = std::move(trackerNames);
242 }
243
IsEmpty() const244 bool TrackerTable::IsEmpty() const
245 {
246 return trackerColNames_.empty();
247 }
248
IsTableNameEmpty() const249 bool TrackerTable::IsTableNameEmpty() const
250 {
251 return tableName_.empty();
252 }
253
IsChanging(const TrackerSchema & schema)254 bool TrackerTable::IsChanging(const TrackerSchema &schema)
255 {
256 if (tableName_ != schema.tableName || extendColName_ != schema.extendColName) {
257 return true;
258 }
259 if (trackerColNames_.size() != schema.trackerColNames.size()) {
260 return true;
261 }
262 for (const auto &col: trackerColNames_) {
263 if (schema.trackerColNames.find(col) == schema.trackerColNames.end()) {
264 return true;
265 }
266 }
267 return false;
268 }
269
ReBuildTempTrigger(sqlite3 * db,TriggerMode::TriggerModeEnum mode,const AfterBuildAction & action)270 int TrackerTable::ReBuildTempTrigger(sqlite3 *db, TriggerMode::TriggerModeEnum mode, const AfterBuildAction &action)
271 {
272 sqlite3_stmt *stmt = nullptr;
273 int errCode = SQLiteUtils::GetStatement(db, "SELECT 1 FROM sqlite_temp_master where name='" +
274 GetTempTriggerName(mode) + "' and type='trigger' COLLATE NOCASE;", stmt);
275 if (errCode != E_OK) {
276 LOGE("Failed to select temp trigger mode:%d err:%d", mode, errCode);
277 return errCode;
278 }
279 errCode = SQLiteUtils::StepWithRetry(stmt);
280 bool isExists = (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) ? true : false;
281 int ret = E_OK;
282 SQLiteUtils::ResetStatement(stmt, true, ret);
283 if (errCode != SQLiteUtils::MapSQLiteErrno(SQLITE_ROW) && errCode != SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) {
284 LOGE("Select temp trigger step mode:%d err:%d", mode, errCode);
285 return errCode;
286 }
287 errCode = SQLiteUtils::ExecuteRawSQL(db, GetDropTempTriggerSql(mode));
288 if (errCode != E_OK) {
289 LOGE("Failed to drop temp trigger mode:%d err:%d", mode, errCode);
290 return errCode;
291 }
292 errCode = SQLiteUtils::ExecuteRawSQL(db, GetCreateTempTriggerSql(mode));
293 if (errCode != E_OK) {
294 LOGE("Failed to create temp trigger mode:%d err:%d", mode, errCode);
295 return errCode;
296 }
297 if (action != nullptr) {
298 errCode = action();
299 if (errCode != E_OK) {
300 return errCode;
301 }
302 }
303 if (!isExists) {
304 errCode = SQLiteUtils::ExecuteRawSQL(db, GetDropTempTriggerSql(mode));
305 if (errCode != E_OK) {
306 LOGE("Failed to clear temp trigger mode:%d err:%d", mode, errCode);
307 }
308 }
309 return errCode;
310 }
311 }
312 #endif