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