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() const148 const std::string TrackerTable::GetTempInsertTriggerSql() 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 sql += CloudStorageUtils::GetCursorIncSql(tableName_) + "\n";
157 sql += "UPDATE " + DBConstant::RELATIONAL_PREFIX + tableName_ + "_log" + " SET ";
158 sql += "cursor=" + CloudStorageUtils::GetSelectIncCursorSql(tableName_) + " WHERE";
159 sql += " hash_key = NEW.hash_key;\n";
160 if (!IsEmpty()) {
161 sql += "SELECT server_observer('" + tableName_ + "', 1);";
162 }
163 sql += "\nEND;";
164 return sql;
165 }
166
GetTempUpdateTriggerSql() const167 const std::string TrackerTable::GetTempUpdateTriggerSql() const
168 {
169 std::string sql = "CREATE TEMP TRIGGER IF NOT EXISTS " + DBConstant::RELATIONAL_PREFIX + tableName_;
170 sql += "_ON_UPDATE_TEMP AFTER UPDATE ON " + tableName_;
171 sql += " WHEN (SELECT 1 FROM " + DBConstant::RELATIONAL_PREFIX + "metadata" +
172 " WHERE key = 'log_trigger_switch' AND value = 'false')\n";
173 sql += "BEGIN\n";
174 sql += CloudStorageUtils::GetCursorIncSql(tableName_) + "\n";
175 sql += "UPDATE " + DBConstant::RELATIONAL_PREFIX + tableName_ + "_log" + " SET ";
176 if (!IsEmpty()) {
177 sql += "extend_field=" + GetAssignValSql() + ",";
178 }
179 sql += "cursor=" + CloudStorageUtils::GetSelectIncCursorSql(tableName_) + " WHERE";
180 sql += " data_key = OLD." + std::string(DBConstant::SQLITE_INNER_ROWID) + ";\n";
181 if (!IsEmpty()) {
182 sql += "SELECT server_observer('" + tableName_ + "', " + GetDiffTrackerValSql() + ");";
183 }
184 sql += "\nEND;";
185 return sql;
186 }
187
GetTempDeleteTriggerSql() const188 const std::string TrackerTable::GetTempDeleteTriggerSql() const
189 {
190 std::string sql = "CREATE TEMP TRIGGER IF NOT EXISTS " + DBConstant::RELATIONAL_PREFIX + tableName_;
191 sql += "_ON_DELETE_TEMP AFTER DELETE ON " + tableName_ +
192 " WHEN (SELECT 1 FROM " + DBConstant::RELATIONAL_PREFIX + "metadata" +
193 " WHERE key = 'log_trigger_switch' AND value = 'false')\n";
194 sql += "BEGIN\n";
195 sql += CloudStorageUtils::GetCursorIncSql(tableName_) + "\n";
196 sql += "UPDATE " + DBConstant::RELATIONAL_PREFIX + tableName_ + "_log" + " SET ";
197 if (!IsEmpty()) {
198 sql += "extend_field=" + GetAssignValSql(true) + ",";
199 }
200 sql += "cursor=" + CloudStorageUtils::GetSelectIncCursorSql(tableName_) + " WHERE";
201 sql += " data_key = OLD." + std::string(DBConstant::SQLITE_INNER_ROWID) + ";\n";
202 if (!IsEmpty()) {
203 sql += "SELECT server_observer('" + tableName_ + "', 1);";
204 }
205 sql += "\nEND;";
206 return sql;
207 }
208
SetTableName(const std::string & tableName)209 void TrackerTable::SetTableName(const std::string &tableName)
210 {
211 tableName_ = tableName;
212 }
213
SetExtendName(const std::string & colName)214 void TrackerTable::SetExtendName(const std::string &colName)
215 {
216 extendColName_ = colName;
217 }
218
SetTrackerNames(const std::set<std::string> & trackerNames)219 void TrackerTable::SetTrackerNames(const std::set<std::string> &trackerNames)
220 {
221 trackerColNames_ = std::move(trackerNames);
222 }
223
IsEmpty() const224 bool TrackerTable::IsEmpty() const
225 {
226 return trackerColNames_.empty();
227 }
228
IsTableNameEmpty() const229 bool TrackerTable::IsTableNameEmpty() const
230 {
231 return tableName_.empty();
232 }
233
IsChanging(const TrackerSchema & schema)234 bool TrackerTable::IsChanging(const TrackerSchema &schema)
235 {
236 if (tableName_ != schema.tableName || extendColName_ != schema.extendColName) {
237 return true;
238 }
239 if (trackerColNames_.size() != schema.trackerColNames.size()) {
240 return true;
241 }
242 for (const auto &col: trackerColNames_) {
243 if (schema.trackerColNames.find(col) == schema.trackerColNames.end()) {
244 return true;
245 }
246 }
247 return false;
248 }
249
ReBuildTempTrigger(sqlite3 * db,TriggerMode::TriggerModeEnum mode,const AfterBuildAction & action)250 int TrackerTable::ReBuildTempTrigger(sqlite3 *db, TriggerMode::TriggerModeEnum mode, const AfterBuildAction &action)
251 {
252 sqlite3_stmt *stmt = nullptr;
253 int errCode = SQLiteUtils::GetStatement(db, "SELECT 1 FROM sqlite_temp_master where name='" +
254 GetTempTriggerName(mode) + "' and type='trigger' COLLATE NOCASE;", stmt);
255 if (errCode != E_OK) {
256 LOGE("Failed to select temp trigger mode:%d err:%d", mode, errCode);
257 return errCode;
258 }
259 errCode = SQLiteUtils::StepWithRetry(stmt);
260 bool isExists = (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) ? true : false;
261 int ret = E_OK;
262 SQLiteUtils::ResetStatement(stmt, true, ret);
263 if (errCode != SQLiteUtils::MapSQLiteErrno(SQLITE_ROW) && errCode != SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) {
264 LOGE("Select temp trigger step mode:%d err:%d", mode, errCode);
265 return errCode;
266 }
267 errCode = SQLiteUtils::ExecuteRawSQL(db, GetDropTempTriggerSql(mode));
268 if (errCode != E_OK) {
269 LOGE("Failed to drop temp trigger mode:%d err:%d", mode, errCode);
270 return errCode;
271 }
272 errCode = SQLiteUtils::ExecuteRawSQL(db, GetCreateTempTriggerSql(mode));
273 if (errCode != E_OK) {
274 LOGE("Failed to create temp trigger mode:%d err:%d", mode, errCode);
275 return errCode;
276 }
277 if (action != nullptr) {
278 errCode = action();
279 if (errCode != E_OK) {
280 return errCode;
281 }
282 }
283 if (!isExists) {
284 errCode = SQLiteUtils::ExecuteRawSQL(db, GetDropTempTriggerSql(mode));
285 if (errCode != E_OK) {
286 LOGE("Failed to clear temp trigger mode:%d err:%d", mode, errCode);
287 }
288 }
289 return errCode;
290 }
291 }
292 #endif