• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 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 #include "store_session.h"
17 #include <chrono>
18 #include <stack>
19 #include <thread>
20 #include "logger.h"
21 #include "rdb_errno.h"
22 #include "shared_block.h"
23 #include "sqlite_database_utils.h"
24 #include "sqlite_utils.h"
25 #include "base_transaction.h"
26 
27 namespace OHOS::NativeRdb {
StoreSession(SqliteConnectionPool & connectionPool)28 StoreSession::StoreSession(SqliteConnectionPool &connectionPool)
29     : connectionPool(connectionPool), connection(nullptr), connectionUseCount(0), isInStepQuery(false)
30 {
31 }
32 
~StoreSession()33 StoreSession::~StoreSession()
34 {
35 }
36 
AcquireConnection(bool isReadOnly)37 void StoreSession::AcquireConnection(bool isReadOnly)
38 {
39     if (connection == nullptr) {
40         connection = connectionPool.AcquireConnection(isReadOnly);
41     }
42 
43     connectionUseCount += 1;
44 }
45 
ReleaseConnection()46 void StoreSession::ReleaseConnection()
47 {
48     if ((connection == nullptr) || (connectionUseCount <= 0)) {
49         LOG_ERROR("SQLiteSession ReleaseConnection repeated release");
50         return;
51     }
52 
53     if (--connectionUseCount == 0) {
54         connectionPool.ReleaseConnection(connection);
55         connection = nullptr;
56     }
57 }
58 
PrepareAndGetInfo(const std::string & sql,bool & outIsReadOnly,int & numParameters,std::vector<std::string> & columnNames)59 int StoreSession::PrepareAndGetInfo(
60     const std::string &sql, bool &outIsReadOnly, int &numParameters, std::vector<std::string> &columnNames)
61 {
62     // Obtains the type of SQL statement.
63     int type = SqliteUtils::GetSqlStatementType(sql);
64     if (SqliteUtils::IsSpecial(type)) {
65         return E_TRANSACTION_IN_EXECUTE;
66     }
67     bool assumeReadOnly = SqliteUtils::IsSqlReadOnly(type);
68 
69     AcquireConnection(assumeReadOnly);
70     int errCode = connection->PrepareAndGetInfo(sql, outIsReadOnly, numParameters, columnNames);
71     if (errCode != 0) {
72         ReleaseConnection();
73         return errCode;
74     }
75 
76     ReleaseConnection();
77     return E_OK;
78 }
79 
BeginExecuteSql(const std::string & sql)80 int StoreSession::BeginExecuteSql(const std::string &sql)
81 {
82     int type = SqliteUtils::GetSqlStatementType(sql);
83     if (SqliteUtils::IsSpecial(type)) {
84         return E_TRANSACTION_IN_EXECUTE;
85     }
86 
87     bool assumeReadOnly = SqliteUtils::IsSqlReadOnly(type);
88     bool isReadOnly = false;
89     AcquireConnection(assumeReadOnly);
90     int errCode = connection->Prepare(sql, isReadOnly);
91     if (errCode != 0) {
92         ReleaseConnection();
93         return errCode;
94     }
95 
96     if (isReadOnly == connection->IsWriteConnection()) {
97         ReleaseConnection();
98         AcquireConnection(isReadOnly);
99         if (!isReadOnly && !connection->IsWriteConnection()) {
100             LOG_ERROR("StoreSession BeginExecutea : read connection can not execute write operation");
101             ReleaseConnection();
102             return E_EXECUTE_WRITE_IN_READ_CONNECTION;
103         }
104     }
105 
106     return E_OK;
107 }
ExecuteSql(const std::string & sql,const std::vector<ValueObject> & bindArgs)108 int StoreSession::ExecuteSql(const std::string &sql, const std::vector<ValueObject> &bindArgs)
109 {
110     int errCode = BeginExecuteSql(sql);
111     if (errCode != 0) {
112         return errCode;
113     }
114 
115     errCode = connection->ExecuteSql(sql, bindArgs);
116     ReleaseConnection();
117     return errCode;
118 }
119 
ExecuteForChangedRowCount(int & changedRows,const std::string & sql,const std::vector<ValueObject> & bindArgs)120 int StoreSession::ExecuteForChangedRowCount(
121     int &changedRows, const std::string &sql, const std::vector<ValueObject> &bindArgs)
122 {
123     int errCode = BeginExecuteSql(sql);
124     if (errCode != 0) {
125         return errCode;
126     }
127 
128     errCode = connection->ExecuteForChangedRowCount(changedRows, sql, bindArgs);
129     ReleaseConnection();
130     return errCode;
131 }
132 
ExecuteForLastInsertedRowId(int64_t & outRowId,const std::string & sql,const std::vector<ValueObject> & bindArgs)133 int StoreSession::ExecuteForLastInsertedRowId(
134     int64_t &outRowId, const std::string &sql, const std::vector<ValueObject> &bindArgs)
135 {
136     int errCode = BeginExecuteSql(sql);
137     if (errCode != 0) {
138         LOG_ERROR("rdbStore BeginExecuteSql failed");
139         return errCode;
140     }
141 
142     errCode = connection->ExecuteForLastInsertedRowId(outRowId, sql, bindArgs);
143     if (errCode != E_OK) {
144         LOG_ERROR("rdbStore ExecuteForLastInsertedRowId FAILED");
145     }
146     ReleaseConnection();
147     return errCode;
148 }
149 
ExecuteGetLong(int64_t & outValue,const std::string & sql,const std::vector<ValueObject> & bindArgs)150 int StoreSession::ExecuteGetLong(int64_t &outValue, const std::string &sql, const std::vector<ValueObject> &bindArgs)
151 {
152     int errCode = BeginExecuteSql(sql);
153     if (errCode != 0) {
154         return errCode;
155     }
156 
157     errCode = connection->ExecuteGetLong(outValue, sql, bindArgs);
158     ReleaseConnection();
159     return errCode;
160 }
161 
ExecuteGetString(std::string & outValue,const std::string & sql,const std::vector<ValueObject> & bindArgs)162 int StoreSession::ExecuteGetString(
163     std::string &outValue, const std::string &sql, const std::vector<ValueObject> &bindArgs)
164 {
165     int errCode = BeginExecuteSql(sql);
166     if (errCode != 0) {
167         return errCode;
168     }
169     std::string sqlstr = sql;
170     int type = SqliteDatabaseUtils::GetSqlStatementType(sqlstr);
171     if (type == STATEMENT_PRAGMA) {
172         ReleaseConnection();
173         AcquireConnection(false);
174     }
175     errCode = connection->ExecuteGetString(outValue, sql, bindArgs);
176     ReleaseConnection();
177     return errCode;
178 }
179 
Backup(const std::string databasePath,const std::vector<uint8_t> destEncryptKey)180 int StoreSession::Backup(const std::string databasePath, const std::vector<uint8_t> destEncryptKey)
181 {
182     std::vector<ValueObject> bindArgs;
183     bindArgs.push_back(ValueObject(databasePath));
184     if (destEncryptKey.size() != 0) {
185         bindArgs.push_back(ValueObject(destEncryptKey));
186     } else {
187         std::string str = "";
188         bindArgs.push_back(ValueObject(str));
189     }
190 
191     int errCode = ExecuteSql(ATTACH_BACKUP_SQL, bindArgs);
192     if (errCode != E_OK) {
193         LOG_ERROR("ExecuteSql ATTACH_BACKUP_SQL error %{public}d", errCode);
194         return errCode;
195     }
196     int64_t count;
197     errCode = ExecuteGetLong(count, EXPORT_SQL, std::vector<ValueObject>());
198     if (errCode != E_OK) {
199         LOG_ERROR("ExecuteSql EXPORT_SQL error %{public}d", errCode);
200         return errCode;
201     }
202 
203     errCode = ExecuteSql(DETACH_BACKUP_SQL, std::vector<ValueObject>());
204     if (errCode != E_OK) {
205         LOG_ERROR("ExecuteSql DETACH_BACKUP_SQL error %{public}d", errCode);
206         return errCode;
207     }
208     return E_OK;
209 }
210 
211 // Checks whether this thread holds a database connection.
IsHoldingConnection() const212 bool StoreSession::IsHoldingConnection() const
213 {
214     if (connection == nullptr) {
215         return false;
216     } else {
217         return true;
218     }
219 }
220 
CheckNoTransaction() const221 int StoreSession::CheckNoTransaction() const
222 {
223     int errorCode = 0;
224     if (connectionPool.getTransactionStack().empty()) {
225         errorCode = E_STORE_SESSION_NO_CURRENT_TRANSACTION;
226         return errorCode;
227     }
228     return E_OK;
229 }
230 
GiveConnectionTemporarily(long milliseconds)231 int StoreSession::GiveConnectionTemporarily(long milliseconds)
232 {
233     int errorCode = CheckNoTransaction();
234     if (errorCode != E_OK) {
235         return errorCode;
236     }
237     BaseTransaction transaction = connectionPool.getTransactionStack().top();
238     if (transaction.IsMarkedSuccessful() || connectionPool.getTransactionStack().size() > 1) {
239         errorCode = E_STORE_SESSION_NOT_GIVE_CONNECTION_TEMPORARILY;
240         return errorCode;
241     }
242 
243     MarkAsCommit();
244     EndTransaction();
245     if (milliseconds > 0) {
246         std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds));
247     }
248     BeginTransaction();
249     return E_OK;
250 }
251 
Attach(const std::string & alias,const std::string & pathName,const std::vector<uint8_t> destEncryptKey)252 int StoreSession::Attach(
253     const std::string &alias, const std::string &pathName, const std::vector<uint8_t> destEncryptKey)
254 {
255     std::string journalMode;
256     int errCode = ExecuteGetString(journalMode, "PRAGMA journal_mode", std::vector<ValueObject>());
257     if (errCode != E_OK) {
258         LOG_ERROR("RdbStoreImpl CheckAttach fail to get journal mode : %{public}d", errCode);
259         return errCode;
260     }
261     journalMode = SqliteUtils::StrToUpper(journalMode);
262     if (journalMode == "WAL") {
263         LOG_ERROR("RdbStoreImpl attach is not supported in WAL mode");
264         return E_NOT_SUPPORTED_ATTACH_IN_WAL_MODE;
265     }
266 
267     std::vector<ValueObject> bindArgs;
268     bindArgs.push_back(ValueObject(pathName));
269     bindArgs.push_back(ValueObject(alias));
270     if (destEncryptKey.size() != 0) {
271         bindArgs.push_back(ValueObject(destEncryptKey));
272     } else {
273         std::string str = "";
274         bindArgs.push_back(ValueObject(str));
275     }
276     errCode = ExecuteSql(ATTACH_SQL, bindArgs);
277     if (errCode != E_OK) {
278         LOG_ERROR("ExecuteSql ATTACH_SQL error %{public}d", errCode);
279         return errCode;
280     }
281 
282     return E_OK;
283 }
284 
BeginTransaction(TransactionObserver * transactionObserver)285 int StoreSession::BeginTransaction(TransactionObserver *transactionObserver)
286 {
287     if (connectionPool.getTransactionStack().empty()) {
288         AcquireConnection(false);
289         if (!connection->IsWriteConnection()) {
290             LOG_ERROR("StoreSession BeginExecutea : read connection can not begin transaction");
291             ReleaseConnection();
292             return E_BEGIN_TRANSACTION_IN_READ_CONNECTION;
293         }
294 
295         int errCode = connection->ExecuteSql("BEGIN EXCLUSIVE;");
296         if (errCode != E_OK) {
297             ReleaseConnection();
298             return errCode;
299         }
300     }
301 
302     if (transactionObserver != nullptr) {
303         transactionObserver->OnBegin();
304     }
305 
306     BaseTransaction transaction(connectionPool.getTransactionStack().size());
307     connectionPool.getTransactionStack().push(transaction);
308 
309     return E_OK;
310 }
311 
MarkAsCommitWithObserver(TransactionObserver * transactionObserver)312 int StoreSession::MarkAsCommitWithObserver(TransactionObserver *transactionObserver)
313 {
314     if (connectionPool.getTransactionStack().empty()) {
315         return E_NO_TRANSACTION_IN_SESSION;
316     }
317     connectionPool.getTransactionStack().top().SetMarkedSuccessful(true);
318     return E_OK;
319 }
320 
EndTransactionWithObserver(TransactionObserver * transactionObserver)321 int StoreSession::EndTransactionWithObserver(TransactionObserver *transactionObserver)
322 {
323     if (connectionPool.getTransactionStack().empty()) {
324         return E_NO_TRANSACTION_IN_SESSION;
325     }
326 
327     BaseTransaction transaction = connectionPool.getTransactionStack().top();
328     bool isSucceed = transaction.IsAllBeforeSuccessful() && transaction.IsMarkedSuccessful();
329     connectionPool.getTransactionStack().pop();
330 
331     if (transactionObserver != nullptr) {
332         if (isSucceed) {
333             transactionObserver->OnCommit();
334         } else {
335             transactionObserver->OnRollback();
336         }
337     }
338 
339     if (!connectionPool.getTransactionStack().empty()) {
340         if (transactionObserver != nullptr) {
341             transactionObserver->OnRollback();
342         }
343 
344         if (!isSucceed) {
345             connectionPool.getTransactionStack().top().SetAllBeforeSuccessful(false);
346         }
347     } else {
348         int errCode;
349         if (isSucceed) {
350             errCode = connection->ExecuteSql("COMMIT;");
351         } else {
352             errCode = connection->ExecuteSql("ROLLBACK;");
353         }
354 
355         ReleaseConnection();
356         return errCode;
357     }
358 
359     return E_OK;
360 }
361 
MarkAsCommit()362 int StoreSession::MarkAsCommit()
363 {
364     if (connectionPool.getTransactionStack().empty()) {
365         return E_NO_TRANSACTION_IN_SESSION;
366     }
367     connectionPool.getTransactionStack().top().SetMarkedSuccessful(true);
368     return E_OK;
369 }
370 
EndTransaction()371 int StoreSession::EndTransaction()
372 {
373     if (connectionPool.getTransactionStack().empty()) {
374         return E_NO_TRANSACTION_IN_SESSION;
375     }
376 
377     BaseTransaction transaction = connectionPool.getTransactionStack().top();
378     bool isSucceed = transaction.IsAllBeforeSuccessful() && transaction.IsMarkedSuccessful();
379     connectionPool.getTransactionStack().pop();
380     if (!connectionPool.getTransactionStack().empty()) {
381         if (!isSucceed) {
382             connectionPool.getTransactionStack().top().SetAllBeforeSuccessful(false);
383         }
384     } else {
385         int errCode = connection->ExecuteSql(isSucceed ? "COMMIT;" : "ROLLBACK;");
386         ReleaseConnection();
387         return errCode;
388     }
389 
390     return E_OK;
391 }
IsInTransaction() const392 bool StoreSession::IsInTransaction() const
393 {
394     return !connectionPool.getTransactionStack().empty();
395 }
396 
BeginStepQuery(int & errCode,const std::string & sql,const std::vector<std::string> & selectionArgs)397 std::shared_ptr<SqliteStatement> StoreSession::BeginStepQuery(
398     int &errCode, const std::string &sql, const std::vector<std::string> &selectionArgs)
399 {
400     if (isInStepQuery == true) {
401         LOG_ERROR("StoreSession BeginStepQuery fail : begin more step query in one session !");
402         errCode = E_MORE_STEP_QUERY_IN_ONE_SESSION;
403         return nullptr; // fail,already in
404     }
405 
406     if (SqliteUtils::GetSqlStatementType(sql) != SqliteUtils::STATEMENT_SELECT) {
407         LOG_ERROR("StoreSession BeginStepQuery fail : not select sql !");
408         errCode = E_EXECUTE_IN_STEP_QUERY;
409         return nullptr;
410     }
411 
412     AcquireConnection(true);
413     std::shared_ptr<SqliteStatement> statement = connection->BeginStepQuery(errCode, sql, selectionArgs);
414     if (statement == nullptr) {
415         ReleaseConnection();
416         return nullptr;
417     }
418     isInStepQuery = true;
419     return statement;
420 }
421 
EndStepQuery()422 int StoreSession::EndStepQuery()
423 {
424     if (isInStepQuery == false) {
425         return E_OK;
426     }
427 
428     int errCode = connection->EndStepQuery();
429     isInStepQuery = false;
430     ReleaseConnection();
431     return errCode;
432 }
433 
ExecuteForSharedBlock(int & rowNum,std::string sql,const std::vector<ValueObject> & bindArgs,AppDataFwk::SharedBlock * sharedBlock,int startPos,int requiredPos,bool isCountAllRows)434 int StoreSession::ExecuteForSharedBlock(int &rowNum, std::string sql, const std::vector<ValueObject> &bindArgs,
435     AppDataFwk::SharedBlock *sharedBlock, int startPos, int requiredPos, bool isCountAllRows)
436 {
437     int errCode = BeginExecuteSql(sql);
438     if (errCode != E_OK) {
439         return errCode;
440     }
441     errCode =
442         connection->ExecuteForSharedBlock(rowNum, sql, bindArgs, sharedBlock, startPos, requiredPos, isCountAllRows);
443     ReleaseConnection();
444     return errCode;
445 }
446 
BeginTransaction()447 int StoreSession::BeginTransaction()
448 {
449     AcquireConnection(false);
450 
451     BaseTransaction transaction(connectionPool.getTransactionStack().size());
452     int errCode = connection->ExecuteSql(transaction.getTransactionStr());
453     if (errCode != E_OK) {
454         LOG_DEBUG("storeSession BeginTransaction Failed");
455         ReleaseConnection();
456         return errCode;
457     }
458     connectionPool.getTransactionStack().push(transaction);
459     ReleaseConnection();
460     return E_OK;
461 }
462 
Commit()463 int StoreSession::Commit()
464 {
465     if (connectionPool.getTransactionStack().empty()) {
466         return E_OK;
467     }
468     BaseTransaction transaction = connectionPool.getTransactionStack().top();
469     std::string sqlStr = transaction.getCommitStr();
470     if (sqlStr.size() <= 1) {
471         connectionPool.getTransactionStack().pop();
472         return E_OK;
473     }
474 
475     AcquireConnection(false);
476     int errCode = connection->ExecuteSql(sqlStr);
477     ReleaseConnection();
478     if (errCode != E_OK) {
479         // if error the transaction is leaving for rollback
480         return errCode;
481     }
482     connectionPool.getTransactionStack().pop();
483     return E_OK;
484 }
485 
RollBack()486 int StoreSession::RollBack()
487 {
488     std::stack<BaseTransaction> transactionStack = connectionPool.getTransactionStack();
489     if (transactionStack.empty()) {
490         return E_NO_TRANSACTION_IN_SESSION;
491     }
492     BaseTransaction transaction = transactionStack.top();
493     transactionStack.pop();
494     if (transaction.getType() != TransType::ROLLBACK_SELF && !transactionStack.empty()) {
495         transactionStack.top().setChildFailure(true);
496     }
497     AcquireConnection(false);
498     int errCode = connection->ExecuteSql(transaction.getRollbackStr());
499     ReleaseConnection();
500     if (errCode != E_OK) {
501         LOG_ERROR("storeSession RollBack Fail");
502     }
503 
504     return errCode;
505 }
506 } // namespace OHOS::NativeRdb
507