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