1 /*
2 * Copyright (c) 2025 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
18 #include <sstream>
19 #include "db_common.h"
20 #include "runtime_context.h"
21
22 namespace DistributedDB {
Int64ToVector(const VBucket & vBucket,const Field & field,CollateType collateType,std::vector<uint8_t> & value)23 int CloudStorageUtils::Int64ToVector(const VBucket &vBucket, const Field &field, CollateType collateType,
24 std::vector<uint8_t> &value)
25 {
26 (void)collateType;
27 int64_t val = 0;
28 if (CloudStorageUtils::GetValueFromVBucket(field.colName, vBucket, val) != E_OK) {
29 return -E_CLOUD_ERROR;
30 }
31 DBCommon::StringToVector(std::to_string(val), value);
32 return E_OK;
33 }
34
BoolToVector(const VBucket & vBucket,const Field & field,CollateType collateType,std::vector<uint8_t> & value)35 int CloudStorageUtils::BoolToVector(const VBucket &vBucket, const Field &field, CollateType collateType,
36 std::vector<uint8_t> &value)
37 {
38 (void)collateType;
39 bool val = false;
40 if (CloudStorageUtils::GetValueFromVBucket(field.colName, vBucket, val) != E_OK) { // LCOV_EXCL_BR_LINE
41 return -E_CLOUD_ERROR;
42 }
43 DBCommon::StringToVector(std::to_string(val ? 1 : 0), value);
44 return E_OK;
45 }
46
DoubleToVector(const VBucket & vBucket,const Field & field,CollateType collateType,std::vector<uint8_t> & value)47 int CloudStorageUtils::DoubleToVector(const VBucket &vBucket, const Field &field, CollateType collateType,
48 std::vector<uint8_t> &value)
49 {
50 (void)collateType;
51 double val = 0.0;
52 if (CloudStorageUtils::GetValueFromVBucket(field.colName, vBucket, val) != E_OK) { // LCOV_EXCL_BR_LINE
53 return -E_CLOUD_ERROR;
54 }
55 std::ostringstream s;
56 s << val;
57 DBCommon::StringToVector(s.str(), value);
58 return E_OK;
59 }
60
TextToVector(const VBucket & vBucket,const Field & field,CollateType collateType,std::vector<uint8_t> & value)61 int CloudStorageUtils::TextToVector(const VBucket &vBucket, const Field &field, CollateType collateType,
62 std::vector<uint8_t> &value)
63 {
64 std::string val;
65 if (CloudStorageUtils::GetValueFromVBucket(field.colName, vBucket, val) != E_OK) {
66 return -E_CLOUD_ERROR;
67 }
68 if (collateType == CollateType::COLLATE_NOCASE) {
69 std::transform(val.begin(), val.end(), val.begin(), ::toupper);
70 } else if (collateType == CollateType::COLLATE_RTRIM) {
71 DBCommon::RTrim(val);
72 }
73
74 DBCommon::StringToVector(val, value);
75 return E_OK;
76 }
77
BlobToVector(const VBucket & vBucket,const Field & field,CollateType collateType,std::vector<uint8_t> & value)78 int CloudStorageUtils::BlobToVector(const VBucket &vBucket, const Field &field, CollateType collateType,
79 std::vector<uint8_t> &value)
80 {
81 (void)collateType;
82 if (field.type == TYPE_INDEX<Bytes>) { // LCOV_EXCL_BR_LINE
83 return CloudStorageUtils::GetValueFromVBucket(field.colName, vBucket, value);
84 } else if (field.type == TYPE_INDEX<Asset>) {
85 Asset val;
86 if (CloudStorageUtils::GetValueFromVBucket(field.colName, vBucket, val) != E_OK) { // LCOV_EXCL_BR_LINE
87 return -E_CLOUD_ERROR;
88 }
89 #ifdef RDB_CLIENT
90 return E_OK;
91 #else
92 int errCode = RuntimeContext::GetInstance()->AssetToBlob(val, value);
93 if (errCode != E_OK) { // LCOV_EXCL_BR_LINE
94 LOGE("asset to blob fail, %d", errCode);
95 }
96 return errCode;
97 #endif
98 } else {
99 Assets val;
100 if (CloudStorageUtils::GetValueFromVBucket(field.colName, vBucket, val) != E_OK) { // LCOV_EXCL_BR_LINE
101 return -E_CLOUD_ERROR;
102 }
103 #ifdef RDB_CLIENT
104 return E_OK;
105 #else
106 int errCode = RuntimeContext::GetInstance()->AssetsToBlob(val, value);
107 if (errCode != E_OK) { // LCOV_EXCL_BR_LINE
108 LOGE("assets to blob fail, %d", errCode);
109 }
110 return errCode;
111 #endif
112 }
113 }
114
CalculateHashKeyForOneField(const Field & field,const VBucket & vBucket,bool allowEmpty,CollateType collateType,std::vector<uint8_t> & hashValue)115 int CloudStorageUtils::CalculateHashKeyForOneField(const Field &field, const VBucket &vBucket, bool allowEmpty,
116 CollateType collateType, std::vector<uint8_t> &hashValue)
117 {
118 Type type;
119 bool isExisted = GetTypeCaseInsensitive(field.colName, vBucket, type);
120 if (allowEmpty && !isExisted) {
121 return E_OK; // if vBucket from cloud doesn't contain primary key and allowEmpty, no need to calculate hash
122 }
123 static std::map<int32_t, std::function<int(const VBucket &, const Field &, CollateType,
124 std::vector<uint8_t> &)>> toVecFunc = {
125 { TYPE_INDEX<int64_t>, &CloudStorageUtils::Int64ToVector },
126 { TYPE_INDEX<bool>, &CloudStorageUtils::BoolToVector },
127 { TYPE_INDEX<double>, &CloudStorageUtils::DoubleToVector },
128 { TYPE_INDEX<std::string>, &CloudStorageUtils::TextToVector },
129 { TYPE_INDEX<Bytes>, &CloudStorageUtils::BlobToVector },
130 { TYPE_INDEX<Asset>, &CloudStorageUtils::BlobToVector },
131 { TYPE_INDEX<Assets>, &CloudStorageUtils::BlobToVector },
132 };
133 auto it = toVecFunc.find(field.type);
134 if (it == toVecFunc.end()) {
135 LOGE("unknown cloud type when convert field to vector.");
136 return -E_CLOUD_ERROR;
137 }
138 std::vector<uint8_t> value;
139 int errCode = it->second(vBucket, field, collateType, value);
140 if (errCode != E_OK) {
141 LOGE("convert cloud field fail, %d", errCode);
142 return errCode;
143 }
144 return DBCommon::CalcValueHash(value, hashValue);
145 }
146
TransferFieldToLower(VBucket & vBucket)147 void CloudStorageUtils::TransferFieldToLower(VBucket &vBucket)
148 {
149 for (auto it = vBucket.begin(); it != vBucket.end();) {
150 std::string lowerField(it->first.length(), ' ');
151 std::transform(it->first.begin(), it->first.end(), lowerField.begin(), ::tolower);
152 if (lowerField != it->first) {
153 vBucket[lowerField] = std::move(vBucket[it->first]);
154 vBucket.erase(it++);
155 } else {
156 it++;
157 }
158 }
159 }
160
GetTypeCaseInsensitive(const std::string & fieldName,const VBucket & vBucket,Type & data)161 bool CloudStorageUtils::GetTypeCaseInsensitive(const std::string &fieldName, const VBucket &vBucket, Type &data)
162 {
163 auto tmpFieldName = fieldName;
164 auto tmpVBucket = vBucket;
165 std::transform(tmpFieldName.begin(), tmpFieldName.end(), tmpFieldName.begin(), ::tolower);
166 TransferFieldToLower(tmpVBucket);
167 auto it = tmpVBucket.find(tmpFieldName);
168 if (it == tmpVBucket.end()) {
169 return false;
170 }
171 data = it->second;
172 return true;
173 }
174
GetSelectIncCursorSql(const std::string & tableName)175 std::string CloudStorageUtils::GetSelectIncCursorSql(const std::string &tableName)
176 {
177 return "(SELECT value FROM " + DBCommon::GetMetaTableName() + " WHERE key=x'" +
178 DBCommon::TransferStringToHex(DBCommon::GetCursorKey(tableName)) + "')";
179 }
180
GetCursorIncSql(const std::string & tableName)181 std::string CloudStorageUtils::GetCursorIncSql(const std::string &tableName)
182 {
183 return "UPDATE " + DBCommon::GetMetaTableName() + " SET value=value+1 WHERE key=x'" +
184 DBCommon::TransferStringToHex(DBCommon::GetCursorKey(tableName)) + "';";
185 }
186
GetCursorIncSqlWhenAllow(const std::string & tableName)187 std::string CloudStorageUtils::GetCursorIncSqlWhenAllow(const std::string &tableName)
188 {
189 std::string prefix = DBConstant::RELATIONAL_PREFIX;
190 return "UPDATE " + prefix + "metadata" + " SET value= case when (select 1 from " +
191 prefix + "metadata" + " where key='cursor_inc_flag' AND value = 'true') then value + 1" +
192 " else value end WHERE key=x'" + DBCommon::TransferStringToHex(DBCommon::GetCursorKey(tableName)) + "';";
193 }
194
GetUpdateLockChangedSql()195 std::string CloudStorageUtils::GetUpdateLockChangedSql()
196 {
197 return " status = CASE WHEN status == 2 THEN 3 ELSE status END";
198 }
199
GetDeleteLockChangedSql()200 std::string CloudStorageUtils::GetDeleteLockChangedSql()
201 {
202 return " status = CASE WHEN status == 2 or status == 3 THEN 1 ELSE status END";
203 }
204
GetTableRefUpdateSql(const TableInfo & table,OpType opType)205 std::string CloudStorageUtils::GetTableRefUpdateSql(const TableInfo &table, OpType opType)
206 {
207 std::string sql;
208 std::string rowid = std::string(DBConstant::SQLITE_INNER_ROWID);
209 for (const auto &reference : table.GetTableReference()) {
210 if (reference.columns.empty()) {
211 return "";
212 }
213 std::string sourceLogName = DBCommon::GetLogTableName(reference.sourceTableName);
214 sql += " UPDATE " + sourceLogName + " SET timestamp=get_raw_sys_time(), flag=flag|0x02 WHERE ";
215 int index = 0;
216 for (const auto &itCol : reference.columns) {
217 if (opType != OpType::UPDATE) {
218 continue;
219 }
220 if (index++ != 0) {
221 sql += " OR ";
222 }
223 sql += " (OLD." + itCol.second + " IS NOT " + " NEW." + itCol.second + ")";
224 }
225 if (opType == OpType::UPDATE) {
226 sql += " AND ";
227 }
228 sql += " (flag&0x08=0x00) AND data_key IN (SELECT " + sourceLogName + ".data_key FROM " + sourceLogName +
229 " LEFT JOIN " + reference.sourceTableName + " ON " + sourceLogName + ".data_key = " +
230 reference.sourceTableName + "." + rowid + " WHERE ";
231 index = 0;
232 for (const auto &itCol : reference.columns) {
233 if (index++ != 0) {
234 sql += " OR ";
235 }
236 if (opType == OpType::UPDATE) {
237 sql += itCol.first + "=OLD." + itCol.second + " OR " + itCol.first + "=NEW." + itCol.second;
238 } else if (opType == OpType::INSERT) {
239 sql += itCol.first + "=NEW." + itCol.second;
240 } else if (opType == OpType::DELETE) {
241 sql += itCol.first + "=OLD." + itCol.second;
242 }
243 }
244 sql += ");";
245 }
246 return sql;
247 }
248 }
249