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
Update(const std::string & table,const Row & row,const std::string & where,const Values & args,Resolution resolution)107 std::pair<int, int> TransDB::Update(const std::string &table, const Row &row, const std::string &where,
108 const Values &args, Resolution resolution)
109 {
110 DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__));
111 auto clause = SqliteUtils::GetConflictClause(static_cast<int>(resolution));
112 if (table.empty() || row.IsEmpty() || clause == nullptr) {
113 return { E_INVALID_ARGS, 0 };
114 }
115
116 std::string sql("UPDATE");
117 sql.append(clause).append(" ").append(table).append(" SET ");
118 std::vector<ValueObject> totalArgs;
119 totalArgs.reserve(row.values_.size() + args.size());
120 const char *split = "";
121 for (auto &[key, val] : row.values_) {
122 sql.append(split);
123 if (val.GetType() == ValueObject::TYPE_ASSETS) {
124 sql.append(key).append("=merge_assets(").append(key).append(", ?)");
125 } else if (val.GetType() == ValueObject::TYPE_ASSET) {
126 sql.append(key).append("=merge_asset(").append(key).append(", ?)");
127 } else {
128 sql.append(key).append("=?");
129 }
130 totalArgs.push_back(val);
131 split = ",";
132 }
133
134 if (!where.empty()) {
135 sql.append(" WHERE ").append(where);
136 }
137
138 totalArgs.insert(totalArgs.end(), args.begin(), args.end());
139 auto [errCode, statement] = GetStatement(sql);
140 if (statement == nullptr) {
141 return { errCode, 0 };
142 }
143
144 errCode = statement->Execute(totalArgs);
145 if (errCode != E_OK) {
146 return { errCode, 0 };
147 }
148 return { errCode, int32_t(statement->Changes()) };
149 }
150
Delete(int & deletedRows,const std::string & table,const std::string & whereClause,const Values & args)151 int TransDB::Delete(int &deletedRows, const std::string &table, const std::string &whereClause, const Values &args)
152 {
153 DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__));
154 if (table.empty()) {
155 return E_INVALID_ARGS;
156 }
157
158 std::string sql;
159 sql.append("DELETE FROM ").append(table);
160 if (!whereClause.empty()) {
161 sql.append(" WHERE ").append(whereClause);
162 }
163 auto [errCode, statement] = GetStatement(sql);
164 if (statement == nullptr) {
165 return errCode;
166 }
167 errCode = statement->Execute(args);
168 if (errCode != E_OK) {
169 return errCode;
170 }
171 deletedRows = statement->Changes();
172 return E_OK;
173 }
174
QuerySql(const std::string & sql,const Values & args)175 std::shared_ptr<AbsSharedResultSet> TransDB::QuerySql(const std::string &sql, const Values &args)
176 {
177 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM)
178 auto start = std::chrono::steady_clock::now();
179 return std::make_shared<SqliteSharedResultSet>(start, conn_.lock(), sql, args, name_);
180 #else
181 (void)sql;
182 (void)args;
183 return nullptr;
184 #endif
185 }
186
QueryByStep(const std::string & sql,const Values & args,bool preCount)187 std::shared_ptr<ResultSet> TransDB::QueryByStep(const std::string &sql, const Values &args, bool preCount)
188 {
189 auto start = std::chrono::steady_clock::now();
190 return std::make_shared<StepResultSet>(start, conn_.lock(), sql, args, true, true);
191 }
192
Execute(const std::string & sql,const Values & args,int64_t trxId)193 std::pair<int32_t, ValueObject> TransDB::Execute(const std::string &sql, const Values &args, int64_t trxId)
194 {
195 (void)trxId;
196 ValueObject object;
197 int sqlType = SqliteUtils::GetSqlStatementType(sql);
198 if (!SqliteUtils::IsSupportSqlForExecute(sqlType) && !SqliteUtils::IsSpecial(sqlType)) {
199 LOG_ERROR("Not support the sql:%{public}s", sql.c_str());
200 return { E_INVALID_ARGS, object };
201 }
202
203 auto [errCode, statement] = GetStatement(sql);
204 if (errCode != E_OK) {
205 return { errCode, object };
206 }
207
208 errCode = statement->Execute(args);
209 if (errCode != E_OK) {
210 LOG_ERROR("failed,sql:%{public}s, error:0x%{public}x.", sql.c_str(), errCode);
211 return { errCode, object };
212 }
213
214 if (sqlType == SqliteUtils::STATEMENT_INSERT) {
215 int64_t outValue = statement->Changes() > 0 ? statement->LastInsertRowId() : -1;
216 return { errCode, ValueObject(outValue) };
217 }
218
219 if (sqlType == SqliteUtils::STATEMENT_UPDATE) {
220 int outValue = statement->Changes();
221 return { errCode, ValueObject(outValue) };
222 }
223
224 if (sqlType == SqliteUtils::STATEMENT_PRAGMA) {
225 if (statement->GetColumnCount() == 1) {
226 return statement->GetColumn(0);
227 }
228 }
229
230 if (sqlType == SqliteUtils::STATEMENT_DDL) {
231 statement->Reset();
232 statement->Prepare("PRAGMA schema_version");
233 auto [err, version] = statement->ExecuteForValue();
234 if (vSchema_ < static_cast<int64_t>(version)) {
235 LOG_INFO("db:%{public}s exe DDL schema<%{public}" PRIi64 "->%{public}" PRIi64 "> sql:%{public}s.",
236 SqliteUtils::Anonymous(name_).c_str(), vSchema_, static_cast<int64_t>(version), sql.c_str());
237 vSchema_ = version;
238 }
239 }
240 return { errCode, object };
241 }
242
GetVersion(int & version)243 int TransDB::GetVersion(int &version)
244 {
245 return E_NOT_SUPPORT;
246 }
247
SetVersion(int version)248 int TransDB::SetVersion(int version)
249 {
250 return E_NOT_SUPPORT;
251 }
252
Sync(const SyncOption & option,const std::vector<std::string> & tables,const AsyncDetail & async)253 int TransDB::Sync(const SyncOption &option, const std::vector<std::string> &tables, const AsyncDetail &async)
254 {
255 if (option.mode != TIME_FIRST || tables.empty()) {
256 return E_INVALID_ARGS;
257 }
258 return RdbStore::Sync(option, tables, async);
259 }
260
GetStatement(const std::string & sql) const261 std::pair<int32_t, std::shared_ptr<Statement>> TransDB::GetStatement(const std::string &sql) const
262 {
263 auto connection = conn_.lock();
264 if (connection == nullptr) {
265 return { E_ALREADY_CLOSED, nullptr };
266 }
267 return connection->CreateStatement(sql, connection);
268 }
269 } // namespace OHOS::NativeRdb