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