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