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 
16 #include "cloud/cloud_storage_utils.h"
17 #include "simple_tracker_log_table_manager.h"
18 
19 namespace DistributedDB {
20 
CalcPrimaryKeyHash(const std::string & references,const TableInfo & table,const std::string & identity)21 std::string SimpleTrackerLogTableManager::CalcPrimaryKeyHash(const std::string &references, const TableInfo &table,
22     const std::string &identity)
23 {
24     (void)identity;
25     std::string sql;
26     if (table.GetPrimaryKey().size() == 1) {
27         sql = "calc_hash(" + references + "'" + table.GetPrimaryKey().at(0)  + "', 0)";
28     }  else {
29         sql = "calc_hash(";
30         for (const auto &it : table.GetPrimaryKey()) {
31             sql += "calc_hash(" + references + "'" + it.second + "', 0)||";
32         }
33         sql.pop_back();
34         sql.pop_back();
35         sql += ", 0)";
36     }
37     return sql;
38 }
39 
GetIndexSql(const TableInfo & table,std::vector<std::string> & schema)40 void SimpleTrackerLogTableManager::GetIndexSql(const TableInfo &table, std::vector<std::string> &schema)
41 {
42     const std::string tableName = GetLogTableName(table);
43 
44     std::string indexCursor = "CREATE INDEX IF NOT EXISTS " + tableName +
45         "_cursor_index ON " + tableName + "(cursor);";
46     std::string indexDataKey = "CREATE INDEX IF NOT EXISTS " + tableName +
47         "_data_key_index ON " + tableName + "(data_key);";
48     schema.emplace_back(indexCursor);
49     schema.emplace_back(indexDataKey);
50 }
51 
GetPrimaryKeySql(const TableInfo & table)52 std::string SimpleTrackerLogTableManager::GetPrimaryKeySql(const TableInfo &table)
53 {
54     return "PRIMARY KEY(hash_key)";
55 }
56 
57 // The parameter "identity" is a hash string that identifies a device. The same for the next two functions.
GetInsertTrigger(const TableInfo & table,const std::string & identity)58 std::string SimpleTrackerLogTableManager::GetInsertTrigger(const TableInfo &table, const std::string &identity)
59 {
60     if (table.GetTrackerTable().GetTrackerColNames().empty()) {
61         return "";
62     }
63     std::string logTblName = GetLogTableName(table);
64     std::string tableName = table.GetTableName();
65     std::string insertTrigger = "CREATE TRIGGER IF NOT EXISTS ";
66     insertTrigger += "naturalbase_rdb_" + tableName + "_ON_INSERT AFTER INSERT \n";
67     insertTrigger += "ON '" + tableName + "'\n";
68     insertTrigger += " FOR EACH ROW \n";
69     insertTrigger += "BEGIN\n";
70     insertTrigger += CloudStorageUtils::GetCursorIncSql(tableName) + "\n";
71     insertTrigger += "\t INSERT OR REPLACE INTO " + logTblName;
72     insertTrigger += " (data_key, device, ori_device, timestamp, wtimestamp, flag, hash_key, cloud_gid";
73     insertTrigger += ", extend_field, cursor, version, sharing_resource, status)";
74     insertTrigger += " VALUES (new." + std::string(DBConstant::SQLITE_INNER_ROWID) + ", '', '',";
75     insertTrigger += " get_raw_sys_time(), get_raw_sys_time(), 0x02, ";
76     insertTrigger += CalcPrimaryKeyHash("NEW.", table, identity) + ", '', ";
77     insertTrigger += table.GetTrackerTable().GetAssignValSql();
78     insertTrigger += ", " + CloudStorageUtils::GetSelectIncCursorSql(tableName) + ", '', '', 0);\n";
79     insertTrigger += "SELECT client_observer('" + tableName + "', NEW._rowid_, 0, ";
80     insertTrigger += table.GetTrackerTable().GetTrackerColNames().empty() ? "0" : "1";
81     insertTrigger += ");\n";
82     insertTrigger += "END;";
83     return insertTrigger;
84 }
85 
GetUpdateTrigger(const TableInfo & table,const std::string & identity)86 std::string SimpleTrackerLogTableManager::GetUpdateTrigger(const TableInfo &table, const std::string &identity)
87 {
88     if (table.GetTrackerTable().GetTrackerColNames().empty()) {
89         return "";
90     }
91     (void)identity;
92     std::string logTblName = GetLogTableName(table);
93     std::string tableName = table.GetTableName();
94     std::string updateTrigger = "CREATE TRIGGER IF NOT EXISTS ";
95     updateTrigger += "naturalbase_rdb_" + tableName + "_ON_UPDATE AFTER UPDATE \n";
96     updateTrigger += "ON '" + tableName + "'\n";
97     updateTrigger += " FOR EACH ROW ";
98     updateTrigger += "BEGIN\n"; // if user change the primary key, we can still use gid to identify which one is updated
99     updateTrigger += CloudStorageUtils::GetCursorIncSql(tableName);
100     updateTrigger.pop_back();
101     updateTrigger += " AND " + table.GetTrackerTable().GetDiffTrackerValSql() + ";";
102     updateTrigger += "\t UPDATE " + logTblName;
103     updateTrigger += " SET timestamp=get_raw_sys_time(), device='', flag=0x02";
104     updateTrigger += table.GetTrackerTable().GetExtendAssignValSql();
105     updateTrigger += table.GetTrackerTable().GetDiffIncCursorSql(tableName);
106     updateTrigger += " WHERE data_key = OLD." + std::string(DBConstant::SQLITE_INNER_ROWID) + ";\n";
107     updateTrigger += "SELECT client_observer('" + tableName + "', OLD." + std::string(DBConstant::SQLITE_INNER_ROWID);
108     updateTrigger += ", 1, ";
109     updateTrigger += table.GetTrackerTable().GetDiffTrackerValSql();
110     updateTrigger += ");";
111     updateTrigger += "END;";
112     return updateTrigger;
113 }
114 
GetDeleteTrigger(const TableInfo & table,const std::string & identity)115 std::string SimpleTrackerLogTableManager::GetDeleteTrigger(const TableInfo &table, const std::string &identity)
116 {
117     if (table.GetTrackerTable().GetTrackerColNames().empty()) {
118         return "";
119     }
120     (void)identity;
121     std::string tableName = table.GetTableName();
122     std::string deleteTrigger = "CREATE TRIGGER IF NOT EXISTS ";
123     deleteTrigger += "naturalbase_rdb_" + tableName + "_ON_DELETE BEFORE DELETE \n";
124     deleteTrigger += "ON '" + tableName + "'\n";
125     deleteTrigger += " FOR EACH ROW \n";
126     deleteTrigger += "BEGIN\n";
127     deleteTrigger += CloudStorageUtils::GetCursorIncSql(tableName) + "\n";
128     deleteTrigger += "\t UPDATE " + GetLogTableName(table);
129     deleteTrigger += " SET data_key=-1,flag=0x03,timestamp=get_raw_sys_time()";
130     deleteTrigger += table.GetTrackerTable().GetExtendAssignValSql(true);
131     deleteTrigger += ", cursor=" + CloudStorageUtils::GetSelectIncCursorSql(tableName) + "";
132     deleteTrigger += " WHERE data_key = OLD." + std::string(DBConstant::SQLITE_INNER_ROWID) + ";";
133     // -1 is rowid when data is deleted, 2 means change type is delete(ClientChangeType)
134     deleteTrigger += "SELECT client_observer('" + tableName + "', -1, 2, ";
135     deleteTrigger += table.GetTrackerTable().GetTrackerColNames().empty() ? "0" : "1";
136     deleteTrigger += ");\n";
137     deleteTrigger += "END;";
138     return deleteTrigger;
139 }
140 
GetDropTriggers(const TableInfo & table)141 std::vector<std::string> SimpleTrackerLogTableManager::GetDropTriggers(const TableInfo &table)
142 {
143     std::vector<std::string> dropTriggers;
144     std::string tableName = table.GetTableName();
145     std::string insertTrigger = "DROP TRIGGER IF EXISTS naturalbase_rdb_" + tableName + "_ON_INSERT; ";
146     std::string updateTrigger = "DROP TRIGGER IF EXISTS naturalbase_rdb_" + tableName + "_ON_UPDATE; ";
147     std::string deleteTrigger = "DROP TRIGGER IF EXISTS naturalbase_rdb_" + tableName + "_ON_DELETE; ";
148     dropTriggers.emplace_back(insertTrigger);
149     dropTriggers.emplace_back(updateTrigger);
150     dropTriggers.emplace_back(deleteTrigger);
151     if (table.GetTrackerTable().GetTrackerColNames().empty()) {
152         std::string deleteLogTable = "DROP TABLE IF EXISTS " + GetLogTableName(table) + ";";
153         dropTriggers.emplace_back(deleteLogTable);
154     }
155     return dropTriggers;
156 }
157 }