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 "sqlite_single_ver_schema_database_upgrader.h"
17 #include "db_errno.h"
18 #include "log_print.h"
19 #include "schema_utils.h"
20 #include "db_constant.h"
21 
22 namespace DistributedDB {
SQLiteSingleVerSchemaDatabaseUpgrader(sqlite3 * db,const SchemaObject & newSchema,const SecurityOption & securityOpt,bool isMemDB)23 SQLiteSingleVerSchemaDatabaseUpgrader::SQLiteSingleVerSchemaDatabaseUpgrader(sqlite3 *db,
24     const SchemaObject &newSchema, const SecurityOption &securityOpt, bool isMemDB)
25     : SQLiteSingleVerDatabaseUpgrader(db, securityOpt, isMemDB), SingleVerSchemaDatabaseUpgrader(newSchema)
26 {
27 }
28 
GetDatabaseSchema(std::string & dbSchema) const29 int SQLiteSingleVerSchemaDatabaseUpgrader::GetDatabaseSchema(std::string &dbSchema) const
30 {
31     int errCode = SQLiteUtils::GetSchema(db_, dbSchema);
32     if (errCode != E_OK && errCode != -E_NOT_FOUND) {
33         LOGE("[SqlSingleSchemaUp][GetSchema] ErrCode=%d", errCode);
34         return errCode;
35     }
36     return E_OK;
37 }
38 
SetDatabaseSchema(const std::string & dbSchema)39 int SQLiteSingleVerSchemaDatabaseUpgrader::SetDatabaseSchema(const std::string &dbSchema)
40 {
41     int errCode = SQLiteUtils::SaveSchema(db_, dbSchema);
42     if (errCode != E_OK) {
43         LOGE("[SqlSingleSchemaUp][SetSchema] ErrCode=%d", errCode);
44     }
45     return errCode;
46 }
47 
48 struct ValueUpgradeContext {
49     SchemaObject schema;
50     uint32_t checkCount = 0;
51     uint32_t getCount = 0;
52     int errCode = E_OK;
53 };
54 
55 namespace {
56 const std::string FUNC_NAME_CHECK_AMEND_VALUE = "check_amend_value";
57 const std::string FUNC_NAME_GET_AMENDED_VALUE = "get_amended_value";
58 // Current implementation is not of ideal performance: at first, we hope to use check_amend_value to filter out values
59 // that do not need amend, and call get_amended_value immediately for those value that need amend and obtain amended
60 // value from ValueUpgradeContext which is cache by check_amend_value just before. It works well for case upgrading from
61 // kv to schema database, but in the case the original schema having index, the sqlite will gather all rowid of values
62 // that after filtering at first, then call get_amended_value for each value of rowid later.
63 // Finally we can only parse value the twice in get_amended_value.
64 const std::string VALUE_UPGRADE_SQL = "UPDATE sync_data SET value=get_amended_value(value) "
65     "WHERE (flag&0x01=0) AND check_amend_value(value) != 0;";
66 constexpr int USING_STR_LEN = -1;
67 
CheckGetForJsonSchema(sqlite3_context * ctx,ValueUpgradeContext & context,const RawValue & inValue,bool checkTrueGetFalse)68 void CheckGetForJsonSchema(sqlite3_context *ctx, ValueUpgradeContext &context, const RawValue &inValue,
69     bool checkTrueGetFalse)
70 {
71     ValueObject valueObj;
72     int errCode = valueObj.Parse(inValue.first, inValue.first + inValue.second, context.schema.GetSkipSize());
73     if (errCode != E_OK) { // Unlikely
74         sqlite3_result_error(ctx, "[SqlSingleSchemaUp][CheckGet] Json value parse fail.", USING_STR_LEN);
75         LOGE("[SqlSingleSchemaUp][CheckGet] IsCheck=%d, Json value(cnt=%u) parse fail=%d.", checkTrueGetFalse,
76             (checkTrueGetFalse ? context.checkCount : context.getCount), errCode);
77         return;
78     }
79     errCode = context.schema.CheckValueAndAmendIfNeed(ValueSource::FROM_DBFILE, valueObj);
80     if (checkTrueGetFalse) {
81         if (errCode == -E_VALUE_MATCH) {
82             sqlite3_result_int(ctx, 0); // SQLiteResult 0 for check_ok_no_amend
83         } else if (errCode == -E_VALUE_MATCH_AMENDED) {
84             sqlite3_result_int(ctx, E_VALUE_MATCH_AMENDED); // SQLiteResult not 0 for check_ok_and_amend
85         } else {
86             sqlite3_result_error(ctx, "[SqlSingleSchemaUp][CheckGet] Json value check fail.", USING_STR_LEN);
87             LOGE("[SqlSingleSchemaUp][CheckGet] Json value(cnt=%u) check fail=%d.", context.checkCount, errCode);
88             context.errCode = -E_SCHEMA_VIOLATE_VALUE;
89         }
90     } else {
91         if (errCode != -E_VALUE_MATCH_AMENDED) { // Unlikely
92             sqlite3_result_error(ctx, "[SqlSingleSchemaUp][CheckGet] Json value no need amend.", USING_STR_LEN);
93             LOGE("[SqlSingleSchemaUp][CheckGet] Json value(cnt=%u) no need amend=%d.", context.getCount, errCode);
94             context.errCode = -E_INTERNAL_ERROR;
95         }
96         std::vector<uint8_t> valueAmended;
97         valueObj.WriteIntoVector(valueAmended);
98         if (valueAmended.size() > DBConstant::MAX_VALUE_SIZE) {
99             sqlite3_result_error(ctx, "[SqlSingleSchemaUp][CheckGet] ValSize exceed limit after amend.", USING_STR_LEN);
100             LOGE("[SqlSingleSchemaUp][CheckGet] Value(cnt=%u) size=%zu exceed limit after amend.", context.getCount,
101                 valueAmended.size());
102             context.errCode = -E_SCHEMA_VIOLATE_VALUE;
103             return;
104         }
105         // For SQLITE_TRANSIENT, SQLite makes a copy of result into space obtained from sqlite3_malloc before it returns
106         sqlite3_result_blob(ctx, valueAmended.data(), valueAmended.size(), SQLITE_TRANSIENT);
107     }
108 }
109 
CheckGetForFlatBufferSchema(sqlite3_context * ctx,ValueUpgradeContext & context,const RawValue & inValue,bool checkTrueGetFalse)110 void CheckGetForFlatBufferSchema(sqlite3_context *ctx, ValueUpgradeContext &context, const RawValue &inValue,
111     bool checkTrueGetFalse)
112 {
113     if (!checkTrueGetFalse) {
114         sqlite3_result_error(ctx, "[SqlSingleSchemaUp][CheckGet] FlatBuffer value no need amend.", USING_STR_LEN);
115         LOGE("[SqlSingleSchemaUp][CheckGet] FlatBuffer value(cnt=%u) no need amend.", context.getCount);
116         context.errCode = -E_INTERNAL_ERROR;
117     }
118     int errCode = context.schema.VerifyValue(ValueSource::FROM_DBFILE, inValue);
119     if (errCode != E_OK) {
120         sqlite3_result_error(ctx, "[SqlSingleSchemaUp][CheckGet] FlatBuffer value verify fail.", USING_STR_LEN);
121         LOGE("[SqlSingleSchemaUp][CheckGet] FlatBuffer value(cnt=%u) verify fail=%d.", context.checkCount, errCode);
122         context.errCode = -E_SCHEMA_VIOLATE_VALUE;
123         return;
124     }
125     sqlite3_result_int(ctx, 0); // SQLiteResult 0 for check_ok_no_amend
126 }
127 
128 // SQLiteResult 0 for check_ok_no_amend, SQLiteResult not 0 for check_ok_and_amend, SQLiteResult error for check_fail
CheckValueOrGetAmendValue(sqlite3_context * ctx,int argc,sqlite3_value ** argv,bool checkTrueGetFalse)129 void CheckValueOrGetAmendValue(sqlite3_context *ctx, int argc, sqlite3_value **argv, bool checkTrueGetFalse)
130 {
131     if (ctx == nullptr || argc != 1 || argv == nullptr) { // 1 parameters, which are value. Unlikely
132         LOGE("[SqlSingleSchemaUp][CheckGet] Invalid parameter, argc=%d.", argc);
133         return;
134     }
135     auto context = static_cast<ValueUpgradeContext *>(sqlite3_user_data(ctx));
136     if (context == nullptr || !context->schema.IsSchemaValid()) { // Unlikely
137         sqlite3_result_error(ctx, "[SqlSingleSchemaUp][CheckGet] No context or schema invalid.", USING_STR_LEN);
138         LOGE("[SqlSingleSchemaUp][CheckGet] No context or schema invalid.");
139         return;
140     }
141     auto valueBlob = static_cast<const uint8_t *>(sqlite3_value_blob(argv[0]));
142     int valueBlobLen = sqlite3_value_bytes(argv[0]);
143     if ((valueBlob == nullptr) || (valueBlobLen <= 0)) { // Is delete record, Unlikely
144         // Currently delete records are filtered out of value upgrade sql, so not allowed here.
145         sqlite3_result_error(ctx, "[SqlSingleSchemaUp][CheckGet] Delete record not allowed.", USING_STR_LEN);
146         LOGE("[SqlSingleSchemaUp][CheckGet] Delete record not allowed.");
147         return;
148     }
149 
150     if (context->schema.GetSchemaType() == SchemaType::JSON) {
151         CheckGetForJsonSchema(ctx, *context, RawValue{valueBlob, valueBlobLen}, checkTrueGetFalse);
152     } else {
153         CheckGetForFlatBufferSchema(ctx, *context, RawValue{valueBlob, valueBlobLen}, checkTrueGetFalse);
154     }
155     // Count only for non-delete value in check_func or get_func
156     if (checkTrueGetFalse) {
157         context->checkCount++;
158     } else {
159         context->getCount++;
160     }
161 }
162 
CheckAmendValue(sqlite3_context * ctx,int argc,sqlite3_value ** argv)163 void CheckAmendValue(sqlite3_context *ctx, int argc, sqlite3_value **argv)
164 {
165     CheckValueOrGetAmendValue(ctx, argc, argv, true);
166 }
167 
GetAmendedValue(sqlite3_context * ctx,int argc,sqlite3_value ** argv)168 void GetAmendedValue(sqlite3_context *ctx, int argc, sqlite3_value **argv)
169 {
170     CheckValueOrGetAmendValue(ctx, argc, argv, false);
171 }
172 }
173 
UpgradeValues()174 int SQLiteSingleVerSchemaDatabaseUpgrader::UpgradeValues()
175 {
176     ValueUpgradeContext context;
177     context.schema = newSchema_;
178     LOGD("[SqlSingleSchemaUp][UpValue] Begin.");
179     int errCode = sqlite3_create_function_v2(db_, FUNC_NAME_CHECK_AMEND_VALUE.c_str(),
180         1, SQLITE_UTF8 | SQLITE_DETERMINISTIC, &context, &CheckAmendValue, nullptr, nullptr, nullptr); // 1 args
181     if (errCode != SQLITE_OK) {
182         LOGE("[SqlSingleSchemaUp][UpValue] Create func=check_amend_value return=%d.", errCode);
183         return SQLiteUtils::MapSQLiteErrno(errCode);
184     }
185     // GetAmendedValue is better not be of deterministic type, otherwise sqlite may take it as constant
186     errCode = sqlite3_create_function_v2(db_, FUNC_NAME_GET_AMENDED_VALUE.c_str(),
187         1, SQLITE_UTF8, &context, &GetAmendedValue, nullptr, nullptr, nullptr); // 1 args
188     if (errCode != SQLITE_OK) {
189         LOGE("[SqlSingleSchemaUp][UpValue] Create func=get_amended_value return=%d.", errCode);
190         return SQLiteUtils::MapSQLiteErrno(errCode);
191     }
192     errCode = SQLiteUtils::ExecuteRawSQL(db_, VALUE_UPGRADE_SQL);
193     if (errCode != E_OK) {
194         LOGE("[SqlSingleSchemaUp][UpValue] Execute value upgrade fail=%d, contextErr=%d.", errCode, context.errCode);
195         // If error caused by upgrade nor sqlite, using contextErr as the final errCode
196         errCode = ((context.errCode == E_OK ? errCode : context.errCode));
197     }
198     LOGD("[SqlSingleSchemaUp][UpValue] End.");
199     return errCode;
200 }
201 
UpgradeIndexes(const IndexDifference & indexDiffer)202 int SQLiteSingleVerSchemaDatabaseUpgrader::UpgradeIndexes(const IndexDifference &indexDiffer)
203 {
204     uint32_t skipSize = newSchema_.GetSkipSize();
205     SchemaType theType = newSchema_.GetSchemaType();
206     // The order of index upgrade is not compulsory, we think order "decrease, change, increase" may be better.
207     LOGD("[SqlSingleSchemaUp][UpIndex] DecreaseIndex: %zu, ChangeIndex: %zu, IncreaseIndex: %zu",
208         indexDiffer.decrease.size(), indexDiffer.change.size(), indexDiffer.increase.size());
209     for (const auto &entry : indexDiffer.decrease) {
210         int errCode = SQLiteUtils::DecreaseIndex(db_, entry);
211         if (errCode != E_OK) {
212             LOGE("[SqlSingleSchemaUp][UpIndex] DecreaseIndex fail, errCode=%d.", errCode);
213             return errCode;
214         }
215     }
216     for (const auto &entry : indexDiffer.change) {
217         int errCode = SQLiteUtils::ChangeIndex(db_, entry.first, entry.second, theType, skipSize);
218         if (errCode != E_OK) {
219             LOGE("[SqlSingleSchemaUp][UpIndex] ChangeIndex fail, errCode=%d.", errCode);
220             return errCode;
221         }
222     }
223     for (const auto &entry : indexDiffer.increase) {
224         int errCode = SQLiteUtils::IncreaseIndex(db_, entry.first, entry.second, theType, skipSize);
225         if (errCode != E_OK) {
226             LOGE("[SqlSingleSchemaUp][UpIndex] IncreaseIndex fail, errCode=%d.", errCode);
227             return errCode;
228         }
229     }
230     return E_OK;
231 }
232 } // namespace DistributedDB
233