• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 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 #define LOG_TAG "TransDB"
16 #include "trans_db.h"
17 
18 #include "logger.h"
19 #include "rdb_sql_statistic.h"
20 #include "rdb_trace.h"
21 #include "sqlite_sql_builder.h"
22 #include "sqlite_utils.h"
23 #include "step_result_set.h"
24 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM)
25 #include "sqlite_shared_result_set.h"
26 #endif
27 namespace OHOS::NativeRdb {
28 using namespace OHOS::Rdb;
29 using namespace DistributedRdb;
TransDB(std::shared_ptr<Connection> conn,const std::string & name)30 TransDB::TransDB(std::shared_ptr<Connection> conn, const std::string &name) : conn_(conn), name_(name)
31 {
32     maxArgs_ = conn->GetMaxVariable();
33 }
34 
Insert(const std::string & table,const Row & row,Resolution resolution)35 std::pair<int, int64_t> TransDB::Insert(const std::string &table, const Row &row, Resolution resolution)
36 {
37     DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__));
38     auto conflictClause = SqliteUtils::GetConflictClause(static_cast<int>(resolution));
39     if (table.empty() || row.IsEmpty() || conflictClause == nullptr) {
40         return { E_INVALID_ARGS, -1 };
41     }
42 
43     std::string sql("INSERT");
44     sql.append(conflictClause).append(" INTO ").append(table).append("(");
45     std::vector<ValueObject> args;
46     args.reserve(row.values_.size());
47     const char *split = "";
48     for (const auto &[key, val] : row.values_) {
49         sql.append(split).append(key);
50         if (val.GetType() == ValueObject::TYPE_ASSETS && resolution == ConflictResolution::ON_CONFLICT_REPLACE) {
51             return { E_INVALID_ARGS, -1 };
52         }
53         SqliteSqlBuilder::UpdateAssetStatus(val, AssetValue::STATUS_INSERT);
54         args.push_back(val); // columnValue
55         split = ",";
56     }
57 
58     sql.append(") VALUES (");
59     if (!args.empty()) {
60         sql.append(SqliteSqlBuilder::GetSqlArgs(args.size()));
61     }
62 
63     sql.append(")");
64     int64_t rowid = -1;
65     auto [errCode, statement] = GetStatement(sql);
66     if (statement == nullptr) {
67         return { errCode, rowid };
68     }
69     errCode = statement->Execute(args);
70     if (errCode != E_OK) {
71         return { errCode, rowid };
72     }
73     rowid = statement->Changes() > 0 ? statement->LastInsertRowId() : -1;
74     return { errCode, rowid };
75 }
76 
BatchInsert(const std::string & table,const RefRows & rows)77 std::pair<int, int64_t> TransDB::BatchInsert(const std::string &table, const RefRows &rows)
78 {
79     if (rows.RowSize() == 0) {
80         return { E_OK, 0 };
81     }
82 
83     auto batchInfo = SqliteSqlBuilder::GenerateSqls(table, rows, maxArgs_);
84     if (table.empty() || batchInfo.empty()) {
85         LOG_ERROR("empty,table=%{public}s,rows:%{public}zu,max:%{public}d.", table.c_str(), rows.RowSize(), maxArgs_);
86         return { E_INVALID_ARGS, -1 };
87     }
88 
89     for (const auto &[sql, batchArgs] : batchInfo) {
90         auto [errCode, statement] = GetStatement(sql);
91         if (statement == nullptr) {
92             return { errCode, -1 };
93         }
94         for (const auto &args : batchArgs) {
95             errCode = statement->Execute(args);
96             if (errCode == E_OK) {
97                 continue;
98             }
99             LOG_ERROR("failed(0x%{public}x) db:%{public}s table:%{public}s args:%{public}zu", errCode,
100                 SqliteUtils::Anonymous(name_).c_str(), table.c_str(), args.size());
101             return { errCode, -1 };
102         }
103     }
104     return { E_OK, int64_t(rows.RowSize()) };
105 }
106 
BatchInsertWithConflictResolution(const std::string & table,const ValuesBuckets & rows,Resolution resolution)107 std::pair<int, int64_t> TransDB::BatchInsertWithConflictResolution(
108     const std::string &table, const ValuesBuckets &rows, Resolution resolution)
109 {
110     if (rows.RowSize() == 0) {
111         return { E_OK, 0 };
112     }
113 
114     auto sqlArgs = SqliteSqlBuilder::GenerateSqls(table, rows, maxArgs_, resolution);
115     if (sqlArgs.size() != 1 || sqlArgs.front().second.size() != 1) {
116         auto [fields, values] = rows.GetFieldsAndValues();
117         LOG_ERROR("invalid args, table=%{public}s, rows:%{public}zu, fields:%{public}zu, max:%{public}d.",
118             table.c_str(), rows.RowSize(), fields != nullptr ? fields->size() : 0, maxArgs_);
119         return { E_INVALID_ARGS, -1 };
120     }
121     auto &[sql, bindArgs] = sqlArgs.front();
122     auto [errCode, statement] = GetStatement(sql);
123     if (statement == nullptr) {
124         LOG_ERROR("statement is nullptr, errCode:0x%{public}x, args:%{public}zu, table:%{public}s.", errCode,
125             bindArgs.size(), table.c_str());
126         return { errCode, -1 };
127     }
128     auto args = std::ref(bindArgs.front());
129     errCode = statement->Execute(args);
130     if (errCode != E_OK) {
131         LOG_ERROR("failed,errCode:%{public}d,table:%{public}s,args:%{public}zu,resolution:%{public}d.", errCode,
132             table.c_str(), args.get().size(), static_cast<int32_t>(resolution));
133         return { errCode, errCode == E_SQLITE_CONSTRAINT ? int64_t(statement->Changes()) : -1 };
134     }
135     return { E_OK, int64_t(statement->Changes()) };
136 }
137 
Update(const std::string & table,const Row & row,const std::string & where,const Values & args,Resolution resolution)138 std::pair<int, int> TransDB::Update(
139     const std::string &table, const Row &row, const std::string &where, const Values &args, Resolution resolution)
140 {
141     DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__));
142     auto clause = SqliteUtils::GetConflictClause(static_cast<int>(resolution));
143     if (table.empty() || row.IsEmpty() || clause == nullptr) {
144         return { E_INVALID_ARGS, 0 };
145     }
146 
147     std::string sql("UPDATE");
148     sql.append(clause).append(" ").append(table).append(" SET ");
149     std::vector<ValueObject> totalArgs;
150     totalArgs.reserve(row.values_.size() + args.size());
151     const char *split = "";
152     for (auto &[key, val] : row.values_) {
153         sql.append(split);
154         if (val.GetType() == ValueObject::TYPE_ASSETS) {
155             sql.append(key).append("=merge_assets(").append(key).append(", ?)");
156         } else if (val.GetType() == ValueObject::TYPE_ASSET) {
157             sql.append(key).append("=merge_asset(").append(key).append(", ?)");
158         } else {
159             sql.append(key).append("=?");
160         }
161         totalArgs.push_back(val);
162         split = ",";
163     }
164 
165     if (!where.empty()) {
166         sql.append(" WHERE ").append(where);
167     }
168 
169     totalArgs.insert(totalArgs.end(), args.begin(), args.end());
170     auto [errCode, statement] = GetStatement(sql);
171     if (statement == nullptr) {
172         return { errCode, 0 };
173     }
174 
175     errCode = statement->Execute(totalArgs);
176     if (errCode != E_OK) {
177         return { errCode, 0 };
178     }
179     return { errCode, int32_t(statement->Changes()) };
180 }
181 
Delete(int & deletedRows,const std::string & table,const std::string & whereClause,const Values & args)182 int TransDB::Delete(int &deletedRows, const std::string &table, const std::string &whereClause, const Values &args)
183 {
184     DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__));
185     if (table.empty()) {
186         return E_INVALID_ARGS;
187     }
188 
189     std::string sql;
190     sql.append("DELETE FROM ").append(table);
191     if (!whereClause.empty()) {
192         sql.append(" WHERE ").append(whereClause);
193     }
194     auto [errCode, statement] = GetStatement(sql);
195     if (statement == nullptr) {
196         return errCode;
197     }
198     errCode = statement->Execute(args);
199     if (errCode != E_OK) {
200         return errCode;
201     }
202     deletedRows = statement->Changes();
203     return E_OK;
204 }
205 
QuerySql(const std::string & sql,const Values & args)206 std::shared_ptr<AbsSharedResultSet> TransDB::QuerySql(const std::string &sql, const Values &args)
207 {
208 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM)
209     auto start = std::chrono::steady_clock::now();
210     return std::make_shared<SqliteSharedResultSet>(start, conn_.lock(), sql, args, name_);
211 #else
212     (void)sql;
213     (void)args;
214     return nullptr;
215 #endif
216 }
217 
QueryByStep(const std::string & sql,const Values & args,bool preCount)218 std::shared_ptr<ResultSet> TransDB::QueryByStep(const std::string &sql, const Values &args, bool preCount)
219 {
220     auto start = std::chrono::steady_clock::now();
221     return std::make_shared<StepResultSet>(start, conn_.lock(), sql, args, true, true);
222 }
223 
Execute(const std::string & sql,const Values & args,int64_t trxId)224 std::pair<int32_t, ValueObject> TransDB::Execute(const std::string &sql, const Values &args, int64_t trxId)
225 {
226     (void)trxId;
227     ValueObject object;
228     int sqlType = SqliteUtils::GetSqlStatementType(sql);
229     if (!SqliteUtils::IsSupportSqlForExecute(sqlType) && !SqliteUtils::IsSpecial(sqlType)) {
230         LOG_ERROR("Not support the sql:app self can check the SQL");
231         return { E_INVALID_ARGS, object };
232     }
233 
234     auto [errCode, statement] = GetStatement(sql);
235     if (errCode != E_OK) {
236         return { errCode, object };
237     }
238 
239     errCode = statement->Execute(args);
240     if (errCode != E_OK) {
241         LOG_ERROR("failed,app self can check the SQL, error:0x%{public}x.", errCode);
242         return { errCode, object };
243     }
244 
245     if (sqlType == SqliteUtils::STATEMENT_INSERT) {
246         int64_t outValue = statement->Changes() > 0 ? statement->LastInsertRowId() : -1;
247         return { errCode, ValueObject(outValue) };
248     }
249 
250     if (sqlType == SqliteUtils::STATEMENT_UPDATE) {
251         int outValue = statement->Changes();
252         return { errCode, ValueObject(outValue) };
253     }
254 
255     if (sqlType == SqliteUtils::STATEMENT_PRAGMA) {
256         if (statement->GetColumnCount() == 1) {
257             return statement->GetColumn(0);
258         }
259     }
260 
261     if (sqlType == SqliteUtils::STATEMENT_DDL) {
262         statement->Reset();
263         statement->Prepare("PRAGMA schema_version");
264         auto [err, version] = statement->ExecuteForValue();
265         if (vSchema_ < static_cast<int64_t>(version)) {
266             LOG_INFO("db:%{public}s exe DDL schema<%{public}" PRIi64 "->%{public}" PRIi64
267                      "> app self can check the SQL.",
268                 SqliteUtils::Anonymous(name_).c_str(), vSchema_, static_cast<int64_t>(version));
269             vSchema_ = version;
270         }
271     }
272     return { errCode, object };
273 }
274 
GetVersion(int & version)275 int TransDB::GetVersion(int &version)
276 {
277     return E_NOT_SUPPORT;
278 }
279 
SetVersion(int version)280 int TransDB::SetVersion(int version)
281 {
282     return E_NOT_SUPPORT;
283 }
284 
Sync(const SyncOption & option,const std::vector<std::string> & tables,const AsyncDetail & async)285 int TransDB::Sync(const SyncOption &option, const std::vector<std::string> &tables, const AsyncDetail &async)
286 {
287     if (option.mode != TIME_FIRST || tables.empty()) {
288         return E_INVALID_ARGS;
289     }
290     return RdbStore::Sync(option, tables, async);
291 }
292 
GetStatement(const std::string & sql) const293 std::pair<int32_t, std::shared_ptr<Statement>> TransDB::GetStatement(const std::string &sql) const
294 {
295     auto connection = conn_.lock();
296     if (connection == nullptr) {
297         return { E_ALREADY_CLOSED, nullptr };
298     }
299     return connection->CreateStatement(sql, connection);
300 }
301 } // namespace OHOS::NativeRdb