1 /*
2 * Copyright (c) 2021 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
16 #include "collaboration_log_table_manager.h"
17
18 namespace DistributedDB {
IsCollaborationWithoutKey(const TableInfo & table)19 bool CollaborationLogTableManager::IsCollaborationWithoutKey(const TableInfo &table)
20 {
21 return ((table.GetIdentifyKey().size() == 1u && table.GetIdentifyKey().at(0) == "rowid") ||
22 table.GetAutoIncrement());
23 }
24
CalcPrimaryKeyHash(const std::string & references,const TableInfo & table,const std::string & identity)25 std::string CollaborationLogTableManager::CalcPrimaryKeyHash(const std::string &references, const TableInfo &table,
26 const std::string &identity)
27 {
28 std::string sql;
29 if (IsCollaborationWithoutKey(table)) {
30 sql = "calc_hash('" + identity + "'||calc_hash(" + references + "rowid))";
31 } else {
32 if (table.GetIdentifyKey().size() == 1) {
33 sql = "calc_hash(" + references + "'" + table.GetIdentifyKey().at(0) + "')";
34 } else {
35 sql = "calc_hash(";
36 for (const auto &it : table.GetIdentifyKey()) {
37 sql += "calc_hash(" + references + "'" + it + "')||";
38 }
39 sql.pop_back();
40 sql.pop_back();
41 sql += ")";
42 }
43 }
44 return sql;
45 }
46
GetInsertTrigger(const TableInfo & table,const std::string & identity)47 std::string CollaborationLogTableManager::GetInsertTrigger(const TableInfo &table, const std::string &identity)
48 {
49 std::string logTblName = DBConstant::RELATIONAL_PREFIX + table.GetTableName() + "_log";
50 std::string insertTrigger = "CREATE TRIGGER IF NOT EXISTS ";
51 insertTrigger += "naturalbase_rdb_" + table.GetTableName() + "_ON_INSERT AFTER INSERT \n";
52 insertTrigger += "ON '" + table.GetTableName() + "'\n";
53 insertTrigger += "WHEN (SELECT count(*) from " + DBConstant::RELATIONAL_PREFIX + "metadata ";
54 insertTrigger += "WHERE key = 'log_trigger_switch' AND value = 'true')\n";
55 insertTrigger += "BEGIN\n";
56 insertTrigger += "\t INSERT OR REPLACE INTO " + logTblName;
57 insertTrigger += " (data_key, device, ori_device, timestamp, wtimestamp, flag, hash_key)";
58 insertTrigger += " VALUES (new.rowid, '', '',";
59 insertTrigger += " get_sys_time(0), get_last_time(),";
60 insertTrigger += " CASE WHEN (SELECT count(*)<>0 FROM " + logTblName + " WHERE hash_key=" +
61 CalcPrimaryKeyHash("NEW.", table, identity) + " AND flag&0x02=0x02) THEN 0x22 ELSE 0x02 END,";
62 insertTrigger += CalcPrimaryKeyHash("NEW.", table, identity) + ");\n";
63 insertTrigger += "END;";
64 return insertTrigger;
65 }
66
GetUpdateTrigger(const TableInfo & table,const std::string & identity)67 std::string CollaborationLogTableManager::GetUpdateTrigger(const TableInfo &table, const std::string &identity)
68 {
69 std::string logTblName = DBConstant::RELATIONAL_PREFIX + table.GetTableName() + "_log";
70 std::string updateTrigger = "CREATE TRIGGER IF NOT EXISTS ";
71 updateTrigger += "naturalbase_rdb_" + table.GetTableName() + "_ON_UPDATE AFTER UPDATE \n";
72 updateTrigger += "ON '" + table.GetTableName() + "'\n";
73 updateTrigger += "WHEN (SELECT count(*) from " + DBConstant::RELATIONAL_PREFIX + "metadata ";
74 updateTrigger += "WHERE key = 'log_trigger_switch' AND value = 'true')\n";
75 updateTrigger += "BEGIN\n";
76 if (table.GetIdentifyKey().size() == 1 && table.GetIdentifyKey().at(0) == "rowid") {
77 // primary key is rowid, it can't be changed
78 updateTrigger += "\t UPDATE " + DBConstant::RELATIONAL_PREFIX + table.GetTableName() + "_log";
79 updateTrigger += " SET timestamp=get_sys_time(0), device='', flag=0x22";
80 updateTrigger += " WHERE data_key = OLD.rowid;";
81 } else {
82 // primary key may be changed, so we need to set the old log record deleted, then insert or replace a new
83 // log record(if primary key not change, insert or replace will modify the log record we set deleted in previous
84 // step)
85 updateTrigger += "\t UPDATE " + logTblName;
86 updateTrigger += " SET data_key=-1, timestamp=get_sys_time(0), device='', flag=0x03";
87 updateTrigger += " WHERE data_key = OLD.rowid;\n";
88 updateTrigger += "\t INSERT OR REPLACE INTO " + logTblName + " VALUES (NEW.rowid, '', '', get_sys_time(0), "
89 "get_last_time(), CASE WHEN (" + CalcPrimaryKeyHash("NEW.", table, identity) + " != " +
90 CalcPrimaryKeyHash("NEW.", table, identity) + ") THEN 0x02 ELSE 0x22 END, " +
91 CalcPrimaryKeyHash("NEW.", table, identity) + ", '');\n";
92 }
93 updateTrigger += "END;";
94 return updateTrigger;
95 }
96
GetDeleteTrigger(const TableInfo & table,const std::string & identity)97 std::string CollaborationLogTableManager::GetDeleteTrigger(const TableInfo &table, const std::string &identity)
98 {
99 (void)identity;
100 std::string deleteTrigger = "CREATE TRIGGER IF NOT EXISTS ";
101 deleteTrigger += "naturalbase_rdb_" + table.GetTableName() + "_ON_DELETE BEFORE DELETE \n";
102 deleteTrigger += "ON '" + table.GetTableName() + "'\n";
103 deleteTrigger += "WHEN (SELECT count(*) from " + DBConstant::RELATIONAL_PREFIX + "metadata ";
104 deleteTrigger += "WHERE key = 'log_trigger_switch' AND VALUE = 'true')\n";
105 deleteTrigger += "BEGIN\n";
106 deleteTrigger += "\t UPDATE " + DBConstant::RELATIONAL_PREFIX + table.GetTableName() + "_log";
107 deleteTrigger += " SET data_key=-1,flag=0x03,timestamp=get_sys_time(0)";
108 deleteTrigger += " WHERE data_key = OLD.rowid;";
109 deleteTrigger += "END;";
110 return deleteTrigger;
111 }
112
GetPrimaryKeySql(const TableInfo & table)113 std::string CollaborationLogTableManager::GetPrimaryKeySql(const TableInfo &table)
114 {
115 return "PRIMARY KEY(hash_key)";
116 }
117
GetIndexSql(const TableInfo & table,std::vector<std::string> & schema)118 void CollaborationLogTableManager::GetIndexSql(const TableInfo &table, std::vector<std::string> &schema)
119 {
120 SqliteLogTableManager::GetIndexSql(table, schema);
121 std::string dataKeyIndex = "CREATE INDEX IF NOT EXISTS " + DBConstant::RELATIONAL_PREFIX + "datakey_index ON " +
122 GetLogTableName(table) + "(data_key);";
123 schema.emplace_back(dataKeyIndex);
124 }
125 }