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
16 #define LOG_TAG "TransactionImpl"
17
18 #include "transaction_impl.h"
19
20 #include "logger.h"
21 #include "rdb_errno.h"
22 #include "rdb_store.h"
23 #include "trans_db.h"
24
25 using namespace OHOS::Rdb;
26 namespace OHOS::NativeRdb {
27
28 __attribute__((used))
29 const int32_t TransactionImpl::regCreator_ = Transaction::RegisterCreator(TransactionImpl::Create);
30
TransactionImpl(std::shared_ptr<Connection> connection,const std::string & name)31 TransactionImpl::TransactionImpl(std::shared_ptr<Connection> connection, const std::string &name)
32 : name_(name), connection_(std::move(connection))
33 {
34 }
35
~TransactionImpl()36 TransactionImpl::~TransactionImpl()
37 {
38 // If the user does not commit the transaction, the next time using this connection to create the transaction will
39 // fail. Here, we attempt to roll back during the transaction object decomposition to prevent this situation
40 // from happening.
41 if (connection_ == nullptr) {
42 return;
43 }
44 Rollback();
45 }
46
Create(int32_t type,std::shared_ptr<Connection> connection,const std::string & name)47 std::pair<int32_t, std::shared_ptr<Transaction>> TransactionImpl::Create(
48 int32_t type, std::shared_ptr<Connection> connection, const std::string &name)
49 {
50 auto trans = std::make_shared<TransactionImpl>(std::move(connection), name);
51 if (trans == nullptr) {
52 return { E_ERROR, nullptr };
53 }
54 auto errorCode = trans->Begin(type);
55 if (errorCode != E_OK) {
56 LOG_ERROR("Transaction begin failed, errorCode=%{public}d", errorCode);
57 return { errorCode, nullptr };
58 }
59 return { E_OK, trans };
60 }
61
GetBeginSql(int32_t type)62 std::string TransactionImpl::GetBeginSql(int32_t type)
63 {
64 if (type < TransactionType::DEFERRED || type >= static_cast<int32_t>(TransactionType::TRANS_BUTT)) {
65 LOG_ERROR("invalid type=%{public}d", type);
66 return {};
67 }
68 return BEGIN_SQLS[type];
69 }
70
Begin(int32_t type)71 int32_t TransactionImpl::Begin(int32_t type)
72 {
73 std::lock_guard lock(mutex_);
74 store_ = std::make_shared<TransDB>(connection_, name_);
75 if (store_ == nullptr) {
76 return E_ERROR;
77 }
78 auto beginSql = GetBeginSql(type);
79 if (beginSql.empty()) {
80 CloseInner();
81 return E_INVALID_ARGS;
82 }
83 auto [errorCode, statement] = connection_->CreateStatement(beginSql, connection_);
84 if (errorCode != E_OK) {
85 LOG_ERROR("create statement failed, errorCode=%{public}d", errorCode);
86 CloseInner();
87 return errorCode;
88 }
89 errorCode = statement->Execute();
90 if (errorCode != E_OK) {
91 LOG_ERROR("statement execute failed, errorCode=%{public}d", errorCode);
92 CloseInner();
93 return errorCode;
94 }
95 return E_OK;
96 }
97
Commit()98 int32_t TransactionImpl::Commit()
99 {
100 std::lock_guard lock(mutex_);
101 if (connection_ == nullptr) {
102 LOG_ERROR("connection already closed");
103 return E_ALREADY_CLOSED;
104 }
105
106 auto [errorCode, statement] = connection_->CreateStatement(COMMIT_SQL, connection_);
107 if (errorCode != E_OK) {
108 LOG_ERROR("create statement failed, errorCode=%{public}d", errorCode);
109 CloseInner(false);
110 return errorCode;
111 }
112
113 errorCode = statement->Execute();
114 if (errorCode != E_OK) {
115 CloseInner(false);
116 LOG_ERROR("statement execute failed, errorCode=%{public}d", errorCode);
117 return errorCode;
118 }
119 CloseInner();
120 return E_OK;
121 }
122
Rollback()123 int32_t TransactionImpl::Rollback()
124 {
125 std::lock_guard lock(mutex_);
126 if (connection_ == nullptr) {
127 LOG_ERROR("connection already closed");
128 return E_ALREADY_CLOSED;
129 }
130
131 auto [errorCode, statement] = connection_->CreateStatement(ROLLBACK_SQL, connection_);
132 if (errorCode != E_OK) {
133 LOG_ERROR("create statement failed, errorCode=%{public}d", errorCode);
134 CloseInner(false);
135 return errorCode;
136 }
137
138 errorCode = statement->Execute();
139 if (errorCode != E_OK) {
140 CloseInner(false);
141 LOG_ERROR("statement execute failed, errorCode=%{public}d", errorCode);
142 return errorCode;
143 }
144 CloseInner();
145 return E_OK;
146 }
147
CloseInner(bool connRecycle)148 int32_t TransactionImpl::CloseInner(bool connRecycle)
149 {
150 std::lock_guard lock(mutex_);
151 store_ = nullptr;
152 if (connection_ != nullptr) {
153 connection_->SetIsRecyclable(connRecycle);
154 }
155 connection_ = nullptr;
156 for (auto &resultSet : resultSets_) {
157 auto sp = resultSet.lock();
158 if (sp != nullptr) {
159 sp->Close();
160 }
161 }
162 return E_OK;
163 }
164
Close()165 int32_t TransactionImpl::Close()
166 {
167 return CloseInner();
168 }
169
GetStore()170 std::shared_ptr<RdbStore> TransactionImpl::GetStore()
171 {
172 std::lock_guard lock(mutex_);
173 return store_;
174 }
175
Insert(const std::string & table,const Row & row,Resolution resolution)176 std::pair<int, int64_t> TransactionImpl::Insert(const std::string &table, const Row &row, Resolution resolution)
177 {
178 auto store = GetStore();
179 if (store == nullptr) {
180 LOG_ERROR("transaction already close");
181 return { E_ALREADY_CLOSED, -1 };
182 }
183 return store->Insert(table, row, resolution);
184 }
185
BatchInsert(const std::string & table,const Rows & rows)186 std::pair<int32_t, int64_t> TransactionImpl::BatchInsert(const std::string &table, const Rows &rows)
187 {
188 auto store = GetStore();
189 if (store == nullptr) {
190 LOG_ERROR("transaction already close");
191 return { E_ALREADY_CLOSED, -1 };
192 }
193 int64_t insertRows{};
194 auto errorCode = store->BatchInsert(insertRows, table, rows);
195 return { errorCode, insertRows };
196 }
197
BatchInsert(const std::string & table,const RefRows & rows)198 std::pair<int, int64_t> TransactionImpl::BatchInsert(const std::string &table, const RefRows &rows)
199 {
200 auto store = GetStore();
201 if (store == nullptr) {
202 LOG_ERROR("transaction already close");
203 return { E_ALREADY_CLOSED, -1 };
204 }
205 return store->BatchInsert(table, rows);
206 }
207
BatchInsertWithConflictResolution(const std::string & table,const RefRows & rows,Resolution resolution)208 std::pair<int32_t, int64_t> TransactionImpl::BatchInsertWithConflictResolution(
209 const std::string &table, const RefRows &rows, Resolution resolution)
210 {
211 auto store = GetStore();
212 if (store == nullptr) {
213 LOG_ERROR("transaction already close");
214 return { E_ALREADY_CLOSED, -1 };
215 }
216 return store->BatchInsertWithConflictResolution(table, rows, resolution);
217 }
218
Update(const std::string & table,const Row & row,const std::string & where,const Values & args,Resolution resolution)219 std::pair<int, int> TransactionImpl::Update(
220 const std::string &table, const Row &row, const std::string &where, const Values &args, Resolution resolution)
221 {
222 auto store = GetStore();
223 if (store == nullptr) {
224 LOG_ERROR("transaction already close");
225 return { E_ALREADY_CLOSED, -1 };
226 }
227 return store->Update(table, row, where, args, resolution);
228 }
229
Update(const Row & row,const AbsRdbPredicates & predicates,Resolution resolution)230 std::pair<int32_t, int32_t> TransactionImpl::Update(
231 const Row &row, const AbsRdbPredicates &predicates, Resolution resolution)
232 {
233 auto store = GetStore();
234 if (store == nullptr) {
235 LOG_ERROR("transaction already close");
236 return { E_ALREADY_CLOSED, -1 };
237 }
238 return store->Update(
239 predicates.GetTableName(), row, predicates.GetWhereClause(), predicates.GetBindArgs(), resolution);
240 }
241
Delete(const std::string & table,const std::string & whereClause,const Values & args)242 std::pair<int32_t, int32_t> TransactionImpl::Delete(
243 const std::string &table, const std::string &whereClause, const Values &args)
244 {
245 auto store = GetStore();
246 if (store == nullptr) {
247 LOG_ERROR("transaction already close");
248 return { E_ALREADY_CLOSED, -1 };
249 }
250 int deletedRows{};
251 auto errorCode = store->Delete(deletedRows, table, whereClause, args);
252 return { errorCode, deletedRows };
253 }
254
Delete(const AbsRdbPredicates & predicates)255 std::pair<int32_t, int32_t> TransactionImpl::Delete(const AbsRdbPredicates &predicates)
256 {
257 auto store = GetStore();
258 if (store == nullptr) {
259 LOG_ERROR("transaction already close");
260 return { E_ALREADY_CLOSED, -1 };
261 }
262 int deletedRows{};
263 auto errorCode = store->Delete(deletedRows, predicates);
264 return { errorCode, deletedRows };
265 }
266
AddResultSet(std::weak_ptr<ResultSet> resultSet)267 void TransactionImpl::AddResultSet(std::weak_ptr<ResultSet> resultSet)
268 {
269 std::lock_guard lock(mutex_);
270 resultSets_.push_back(std::move(resultSet));
271 }
272
QueryByStep(const std::string & sql,const Values & args,bool preCount)273 std::shared_ptr<ResultSet> TransactionImpl::QueryByStep(const std::string &sql, const Values &args, bool preCount)
274 {
275 auto store = GetStore();
276 if (store == nullptr) {
277 LOG_ERROR("transaction already close");
278 return nullptr;
279 }
280 auto resultSet = store->QueryByStep(sql, args);
281 if (resultSet != nullptr) {
282 AddResultSet(resultSet);
283 }
284 return resultSet;
285 }
286
QueryByStep(const AbsRdbPredicates & predicates,const Fields & columns,bool preCount)287 std::shared_ptr<ResultSet> TransactionImpl::QueryByStep(
288 const AbsRdbPredicates &predicates, const Fields &columns, bool preCount)
289 {
290 auto store = GetStore();
291 if (store == nullptr) {
292 LOG_ERROR("transaction already close");
293 return nullptr;
294 }
295 auto resultSet = store->QueryByStep(predicates, columns);
296 if (resultSet != nullptr) {
297 AddResultSet(resultSet);
298 }
299 return resultSet;
300 }
301
Execute(const std::string & sql,const Values & args)302 std::pair<int32_t, ValueObject> TransactionImpl::Execute(const std::string &sql, const Values &args)
303 {
304 auto store = GetStore();
305 if (store == nullptr) {
306 LOG_ERROR("transaction already close");
307 return { E_ALREADY_CLOSED, ValueObject() };
308 }
309 return store->Execute(sql, args);
310 }
311 } // namespace OHOS::NativeRdb
312