• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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