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