• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 #define LOG_TAG "SqliteSharedResultSet"
16 #include "sqlite_shared_result_set.h"
17 
18 #include <rdb_errno.h>
19 
20 #include <cinttypes>
21 #include <cstdint>
22 #include <memory>
23 #include <mutex>
24 #include <tuple>
25 
26 #include "logger.h"
27 #include "rdb_sql_statistic.h"
28 #include "rdb_sql_utils.h"
29 #include "result_set.h"
30 #include "share_block.h"
31 #include "sqlite_connection.h"
32 #include "sqlite_errno.h"
33 #include "sqlite_statement.h"
34 #include "sqlite_utils.h"
35 
36 namespace OHOS {
37 namespace NativeRdb {
38 using namespace OHOS::Rdb;
39 using namespace std::chrono;
40 constexpr int64_t TIME_OUT = 1500;
SqliteSharedResultSet(Time start,Conn conn,std::string sql,const Values & args,const std::string & path)41 SqliteSharedResultSet::SqliteSharedResultSet(
42     Time start, Conn conn, std::string sql, const Values &args, const std::string &path)
43     : AbsSharedResultSet(path), conn_(std::move(conn)), qrySql_(std::move(sql)), bindArgs_(args)
44 {
45     if (conn_ == nullptr) {
46         isClosed_ = true;
47         return;
48     }
49 
50     auto prepareBegin = steady_clock::now();
51     auto [statement, errCode] = PrepareStep();
52     if (errCode != E_OK) {
53         LOG_ERROR("step resultset ret %{public}d", errCode);
54         return;
55     }
56     statement_ = statement;
57     auto countBegin = steady_clock::now();
58     std::tie(lastErr_, rowCount_) = statement->Count();
59     auto endTime = steady_clock::now();
60     int64_t totalCost = duration_cast<milliseconds>(endTime - start).count();
61     if (totalCost >= TIME_OUT) {
62         int64_t acquireCost = duration_cast<milliseconds>(prepareBegin - start).count();
63         int64_t prepareCost = duration_cast<milliseconds>(countBegin - prepareBegin).count();
64         int64_t countCost = duration_cast<milliseconds>(endTime - countBegin).count();
65         LOG_WARN("total[%{public}" PRId64 "]<%{public}" PRId64 ",%{public}" PRId64 ",%{public}" PRId64
66                  "> rowCount[%{public}d] sql[%{public}s] path[%{public}s]",
67             totalCost, acquireCost, prepareCost, countCost, rowCount_,
68             SqliteUtils::SqlAnonymous(qrySql_).c_str(), SqliteUtils::Anonymous(path).c_str());
69     }
70 }
71 
PrepareStep()72 std::pair<std::shared_ptr<Statement>, int> SqliteSharedResultSet::PrepareStep()
73 {
74     std::lock_guard<decltype(globalMtx_)> lockGuard(globalMtx_);
75     if (conn_ == nullptr) {
76         LOG_ERROR("Already close.");
77         lastErr_ = E_ALREADY_CLOSED;
78         return { nullptr, E_ALREADY_CLOSED };
79     }
80 
81     if (statement_ != nullptr) {
82         return { statement_, E_OK };
83     }
84 
85     auto type = SqliteUtils::GetSqlStatementType(qrySql_);
86     if (type == SqliteUtils::STATEMENT_ERROR) {
87         LOG_ERROR("invalid sql_ %{public}s, type: %{public}d", SqliteUtils::SqlAnonymous(qrySql_).c_str(), type);
88         lastErr_ = E_INVALID_ARGS;
89         return { nullptr, E_INVALID_ARGS };
90     }
91 
92     auto [errCode, statement] = conn_->CreateStatement(qrySql_, conn_);
93     if (statement == nullptr) {
94         lastErr_ = errCode;
95         return { statement, errCode };
96     }
97 
98     if (!statement->ReadOnly()) {
99         LOG_ERROR("failed, %{public}s is not query sql!", SqliteUtils::SqlAnonymous(qrySql_).c_str());
100         lastErr_ = E_NOT_SELECT;
101         return { nullptr, E_NOT_SELECT };
102     }
103 
104     errCode = statement->Bind(bindArgs_);
105     if (errCode != E_OK) {
106         LOG_ERROR("Bind arg faild! Ret is %{public}d", errCode);
107         statement->Reset();
108         statement = nullptr;
109         lastErr_ = errCode;
110         return { nullptr, errCode };
111     }
112     return { statement, E_OK };
113 }
114 
~SqliteSharedResultSet()115 SqliteSharedResultSet::~SqliteSharedResultSet() {}
116 
GetColumnNames()117 std::pair<int, std::vector<std::string>> SqliteSharedResultSet::GetColumnNames()
118 {
119     if (isClosed_) {
120         LOG_ERROR("fail, result set has been closed, ret %{public}d, sql %{public}s",
121             E_ALREADY_CLOSED, SqliteUtils::SqlAnonymous(qrySql_).c_str());
122         return { E_ALREADY_CLOSED, {} };
123     }
124 
125     auto [statement, errCode] = PrepareStep();
126     if (statement == nullptr) {
127         return { errCode, {} };
128     }
129 
130     // Get the total number of columns
131     auto columnCount = statement->GetColumnCount();
132     std::vector<std::string> colNames;
133     for (int i = 0; i < columnCount; i++) {
134         auto [ret, name] = statement->GetColumnName(i);
135         if (ret != E_OK) {
136             return { ret, {} };
137         }
138         colNames.push_back(name);
139     }
140 
141     return { E_OK, std::move(colNames) };
142 }
143 
Close()144 int SqliteSharedResultSet::Close()
145 {
146     AbsSharedResultSet::Close();
147     statement_ = nullptr;
148     conn_ = nullptr;
149     rowCount_ = NO_COUNT;
150     auto qrySql = std::move(qrySql_);
151     auto bindArgs = std::move(bindArgs_);
152     return E_OK;
153 }
154 
OnGo(int oldPosition,int newPosition)155 int SqliteSharedResultSet::OnGo(int oldPosition, int newPosition)
156 {
157     if (isClosed_) {
158         LOG_ERROR("fail, result set has been closed, ret %{public}d, sql %{public}s",
159             E_ALREADY_CLOSED, SqliteUtils::SqlAnonymous(qrySql_).c_str());
160         return E_ALREADY_CLOSED;
161     }
162     auto sharedBlock = GetBlock();
163     if (sharedBlock == nullptr) {
164         return E_ERROR;
165     }
166 
167     if ((uint32_t)newPosition < sharedBlock->GetStartPos() || (uint32_t)newPosition >= sharedBlock->GetLastPos() ||
168         oldPosition == rowCount_) {
169         auto errCode = FillBlock(newPosition);
170         if (errCode == E_NO_MORE_ROWS && rowCount_ != Statement::INVALID_COUNT) {
171             rowCount_ = sharedBlock->GetLastPos() > INT_MAX ? Statement::INVALID_COUNT
172                                                             : static_cast<int>(sharedBlock->GetLastPos());
173             rowPos_ = rowPos_ > rowCount_ ? rowCount_ : rowPos_;
174             errCode = E_ROW_OUT_RANGE;
175         }
176         return errCode;
177     }
178     return E_OK;
179 }
180 
181 /**
182  * Calculate a proper start position to fill the block.
183  */
PickFillBlockStartPosition(int resultSetPosition,int blockCapacity) const184 int SqliteSharedResultSet::PickFillBlockStartPosition(int resultSetPosition, int blockCapacity) const
185 {
186     return std::max(resultSetPosition - blockCapacity / PICK_POS, 0);
187 }
188 
FillBlock(int requiredPos)189 int SqliteSharedResultSet::FillBlock(int requiredPos)
190 {
191     auto block = GetBlock();
192     if (block == nullptr) {
193         LOG_ERROR("FillSharedBlock GetBlock failed.");
194         return E_ERROR;
195     }
196     ClearBlock();
197     int startPos = isOnlyFillBlock_ ? requiredPos : PickFillBlockStartPosition(requiredPos, blockCapacity_);
198     auto errCode = ExecuteForSharedBlock(block.get(), startPos, requiredPos);
199     if (errCode != E_OK) {
200         return errCode;
201     }
202     blockCapacity_ = block->GetRowNum();
203     if ((block->GetStartPos() == block->GetLastPos() && (uint32_t)rowCount_ != block->GetStartPos()) ||
204         ((uint32_t)requiredPos < block->GetStartPos() || block->GetLastPos() <= (uint32_t)requiredPos) ||
205         block->GetStartPos() > 0) {
206         LOG_WARN("blockRowNum=%{public}d, requiredPos= %{public}d, startPos_= %{public}" PRIu32
207                  ", lastPos_= %{public}" PRIu32 ", blockPos_= %{public}" PRIu32 ".",
208             rowCount_, requiredPos, block->GetStartPos(), block->GetLastPos(), block->GetBlockPos());
209     }
210     return (uint32_t)requiredPos >= block->GetLastPos() ? E_NO_MORE_ROWS : E_OK;
211 }
212 
SetBlock(AppDataFwk::SharedBlock * block)213 void SqliteSharedResultSet::SetBlock(AppDataFwk::SharedBlock *block)
214 {
215     AbsSharedResultSet::SetBlock(block);
216     rowNum_ = NO_COUNT;
217 }
218 
219 /**
220  * If isOnlyFillResultSetBlockInput is true, use the input requiredPos to fill the block, otherwise pick the value
221  * from requirePos and blockCapacity_.
222  */
SetFillBlockForwardOnly(bool isOnlyFillResultSetBlockInput)223 void SqliteSharedResultSet::SetFillBlockForwardOnly(bool isOnlyFillResultSetBlockInput)
224 {
225     isOnlyFillBlock_ = isOnlyFillResultSetBlockInput;
226 }
227 
Finalize()228 void SqliteSharedResultSet::Finalize()
229 {
230     Close();
231 }
232 /**
233  * Executes a statement and populates the specified with a range of results.
234  */
ExecuteForSharedBlock(AppDataFwk::SharedBlock * block,int start,int required)235 int32_t SqliteSharedResultSet::ExecuteForSharedBlock(AppDataFwk::SharedBlock *block, int start, int required)
236 {
237     auto [statement, errCode] = PrepareStep();
238     if (errCode != E_OK) {
239         LOG_ERROR("PrepareStep error = %{public}d ", errCode);
240         return errCode;
241     }
242 
243     auto code = block->Clear();
244     if (code != AppDataFwk::SharedBlock::SHARED_BLOCK_OK) {
245         LOG_ERROR("Clear %{public}d.", code);
246         return E_ERROR;
247     }
248 
249     SharedBlockInfo blockInfo(block);
250     blockInfo.requiredPos = required;
251     blockInfo.columnNum = statement->GetColumnCount();
252     blockInfo.isCountAllRows = false;
253     blockInfo.startPos = start;
254     code = block->SetColumnNum(blockInfo.columnNum);
255     if (code != AppDataFwk::SharedBlock::SHARED_BLOCK_OK) {
256         LOG_ERROR("SetColumnNum %{public}d.", code);
257         return E_ERROR;
258     }
259     std::lock_guard<decltype(globalMtx_)> lockGuard(globalMtx_);
260     errCode = statement->FillBlockInfo(&blockInfo);
261     if (errCode != E_OK) {
262         LOG_ERROR("Fill shared block failed, ret is %{public}d", errCode);
263         return errCode;
264     }
265 
266     block->SetStartPos(blockInfo.startPos);
267     block->SetBlockPos(required - blockInfo.startPos);
268     block->SetLastPos(blockInfo.startPos + block->GetRowNum());
269     return E_OK;
270 }
271 } // namespace NativeRdb
272 } // namespace OHOS