• 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 "StepResultSet"
16 #include "step_result_set.h"
17 
18 #include <unistd.h>
19 
20 #include "connection_pool.h"
21 #include "logger.h"
22 #include "rdb_errno.h"
23 #include "sqlite3sym.h"
24 #include "sqlite_errno.h"
25 #include "sqlite_statement.h"
26 #include "sqlite_utils.h"
27 #include "value_object.h"
28 
29 namespace OHOS {
30 namespace NativeRdb {
31 using namespace OHOS::Rdb;
32 
33 constexpr int64_t TIME_OUT = 1500;
StepResultSet(Time start,Conn conn,const std::string & sql,const Values & args,bool preCount,bool safe)34 StepResultSet::StepResultSet(Time start, Conn conn, const std::string &sql, const Values &args,
35     bool preCount, bool safe) : AbsResultSet(safe), conn_(std::move(conn)), sql_(sql), args_(args)
36 {
37     if (conn_ == nullptr) {
38         isClosed_ = true;
39         return;
40     }
41 
42     auto prepareStart = std::chrono::steady_clock::now();
43     auto errCode = PrepareStep();
44     if (errCode != E_OK) {
45         LOG_ERROR("step resultset ret %{public}d", errCode);
46         return;
47     }
48     auto prepareEnd = std::chrono::steady_clock::now();
49     auto statement = GetStatement();
50     if (statement == nullptr) {
51         return;
52     }
53     if (preCount) {
54         std::tie(lastErr_, rowCount_) = statement->Count();
55     } else {
56         isSupportCountRow_ = false;
57     }
58     if (lastErr_ == E_NOT_SUPPORT && rowCount_ == Statement::INVALID_COUNT) {
59         isSupportCountRow_ = false;
60         lastErr_ = E_OK;
61     }
62     auto queryEnd = std::chrono::steady_clock::now();
63     int64_t totalCost = std::chrono::duration_cast<std::chrono::milliseconds>(queryEnd - start).count();
64     if (totalCost >= TIME_OUT) {
65         int64_t acquireCost = std::chrono::duration_cast<std::chrono::milliseconds>(prepareStart - start).count();
66         int64_t prepareCost = std::chrono::duration_cast<std::chrono::milliseconds>(prepareEnd - prepareStart).count();
67         int64_t countCost = std::chrono::duration_cast<std::chrono::milliseconds>(queryEnd - prepareEnd).count();
68         LOG_WARN("total[%{public}" PRId64 "]<%{public}" PRId64 ",%{public}" PRId64 ",%{public}" PRId64
69                  "> count[%{public}d] sql[%{public}s]",
70             totalCost, acquireCost, prepareCost, countCost, rowCount_, SqliteUtils::SqlAnonymous(sql_).c_str());
71     }
72 }
73 
~StepResultSet()74 StepResultSet::~StepResultSet()
75 {
76     Close();
77 }
78 
79 /**
80  * Obtain session and prepare precompile statement for step query
81  */
PrepareStep()82 int StepResultSet::PrepareStep()
83 {
84     std::lock_guard<decltype(globalMtx_)> lockGuard(globalMtx_);
85     if (statement_ != nullptr) {
86         return E_OK;
87     }
88 
89     if (isClosed_ || conn_ == nullptr) {
90         lastErr_ = E_ALREADY_CLOSED;
91         return lastErr_;
92     }
93 
94     auto type = SqliteUtils::GetSqlStatementType(sql_);
95     if (type == SqliteUtils::STATEMENT_ERROR) {
96         LOG_ERROR("invalid sql_ %{public}s!", SqliteUtils::SqlAnonymous(sql_).c_str());
97         lastErr_ = E_INVALID_ARGS;
98         return lastErr_;
99     }
100 
101     auto [errCode, statement] = conn_->CreateStatement(sql_, conn_);
102     if (statement == nullptr || errCode != E_OK) {
103         lastErr_ = errCode;
104         LOG_ERROR("CreateStatement failed. sql_ %{public}s!", SqliteUtils::SqlAnonymous(sql_).c_str());
105         return E_STATEMENT_NOT_PREPARED;
106     }
107 
108     if (!statement->ReadOnly()) {
109         LOG_ERROR("failed, %{public}s is not query sql!", SqliteUtils::SqlAnonymous(sql_).c_str());
110         lastErr_ = E_NOT_SELECT;
111         return lastErr_;
112     }
113 
114     errCode = statement->Bind(args_);
115     if (errCode != E_OK) {
116         LOG_ERROR("Bind arg faild! Ret is %{public}d", errCode);
117         statement->Reset();
118         statement = nullptr;
119         lastErr_ = errCode;
120         return lastErr_;
121     }
122 
123     statement_ = std::move(statement);
124     return E_OK;
125 }
126 
GetColumnNames()127 std::pair<int, std::vector<std::string>> StepResultSet::GetColumnNames()
128 {
129     if (lastErr_ != E_OK) {
130         return { lastErr_, {} };
131     }
132     auto statement = GetStatement();
133     if (statement == nullptr) {
134         LOG_ERROR("Statement is nullptr.");
135         return { E_ALREADY_CLOSED, {} };
136     }
137     auto colCount = statement->GetColumnCount();
138     std::vector<std::string> names;
139     for (int i = 0; i < colCount; i++) {
140         auto [code, colName] = statement->GetColumnName(i);
141         if (code) {
142             LOG_ERROR("GetColumnName ret %{public}d", code);
143             return { code, {} };
144         }
145         names.push_back(colName);
146     }
147 
148     return { E_OK, std::move(names) };
149 }
150 
GetColumnType(int columnIndex,ColumnType & columnType)151 int StepResultSet::GetColumnType(int columnIndex, ColumnType &columnType)
152 {
153     if (isClosed_) {
154         return E_ALREADY_CLOSED;
155     }
156     if (rowPos_ == INIT_POS || ((isSupportCountRow_ || rowCount_ != Statement::INVALID_COUNT) && IsEnded().second)) {
157         LOG_ERROR("query not executed.");
158         return E_ROW_OUT_RANGE;
159     }
160     auto statement = GetStatement();
161     if (statement == nullptr) {
162         LOG_ERROR("Statement is nullptr.");
163         return E_ALREADY_CLOSED;
164     }
165 
166     auto [errCode, outPutType] = statement->GetColumnType(columnIndex);
167     if (errCode != E_OK) {
168         LOG_ERROR("GetColumnType ret %{public}d", errCode);
169         return errCode;
170     }
171     columnType = static_cast<ColumnType>(outPutType);
172     return E_OK;
173 }
174 
175 /**
176  * Moves the result set to a specified position
177  */
GoToRow(int position)178 int StepResultSet::GoToRow(int position)
179 {
180     if (isClosed_) {
181         return E_ALREADY_CLOSED;
182     }
183 
184     if (lastErr_ != E_OK) {
185         return lastErr_;
186     }
187 
188     if (isSupportCountRow_ && position >= rowCount_) {
189         rowPos_ = (position >= rowCount_ && rowCount_ != 0) ? rowCount_ : rowPos_;
190         LOG_ERROR("position[%{public}d] rowCount[%{public}d] rowPos_[%{public}d]!", position, rowCount_, rowPos_);
191         return E_ROW_OUT_RANGE;
192     }
193 
194     if (position < 0) {
195         return E_ROW_OUT_RANGE;
196     }
197 
198     if (position < rowPos_) {
199         Reset();
200         return GoToRow(position);
201     }
202     while (position != rowPos_) {
203         int errCode = GoToNextRow();
204         if (errCode != E_OK) {
205             LOG_WARN("GoToNextRow ret %{public}d", errCode);
206             return errCode;
207         }
208     }
209     return E_OK;
210 }
211 
212 /**
213  * Move the result set to the next row
214  */
GoToNextRow()215 int StepResultSet::GoToNextRow()
216 {
217     if (isClosed_) {
218         LOG_ERROR("resultSet closed.");
219         return E_ALREADY_CLOSED;
220     }
221 
222     auto statement = GetStatement();
223     if (statement == nullptr) {
224         LOG_ERROR("Statement is nullptr.");
225         return E_ALREADY_CLOSED;
226     }
227 
228     int retryCount = 0;
229     auto errCode = statement->Step();
230 
231     while (errCode == E_SQLITE_LOCKED || errCode == E_SQLITE_BUSY) {
232         // The table is locked, retry
233         if (retryCount > STEP_QUERY_RETRY_MAX_TIMES) {
234             LOG_ERROR("Step in busy ret is %{public}d", errCode);
235             return E_STEP_RESULT_QUERY_EXCEEDED;
236         } else {
237             // Sleep to give the thread holding the lock a chance to finish
238             usleep(STEP_QUERY_RETRY_INTERVAL);
239             errCode = statement->Step();
240             retryCount++;
241         }
242     }
243 
244     if (errCode == E_OK) {
245         rowPos_++;
246         return E_OK;
247     } else if (errCode == E_NO_MORE_ROWS) {
248         if (isSupportCountRow_ || rowCount_ != Statement::INVALID_COUNT) {
249             rowPos_ = rowCount_ != 0 ? rowCount_ : rowPos_;
250         } else {
251             ++rowPos_;
252             rowCount_ = rowPos_;
253         }
254         return E_ROW_OUT_RANGE;
255     } else {
256         Reset();
257         rowPos_ = rowCount_;
258         return errCode;
259     }
260 }
261 
Close()262 int StepResultSet::Close()
263 {
264     if (isClosed_) {
265         return E_OK;
266     }
267     isClosed_ = true;
268     {
269         std::lock_guard<decltype(globalMtx_)> lockGuard(globalMtx_);
270         conn_ = nullptr;
271         statement_ = nullptr;
272         auto args = std::move(args_);
273         auto sql = std::move(sql_);
274     }
275     Reset();
276     return E_OK;
277 }
278 
GetRowCount(int & count)279 int StepResultSet::GetRowCount(int &count)
280 {
281     if (isSupportCountRow_ || rowCount_ != Statement::INVALID_COUNT) {
282         return AbsResultSet::GetRowCount(count);
283     }
284 
285     int oldPosition = 0;
286     // Get the start position of the query result
287     GetRowIndex(oldPosition);
288     int ret = E_OK;
289     while (ret == E_OK) {
290         ret = GoToNextRow();
291         if (ret == E_ROW_OUT_RANGE) {
292             rowCount_ = rowPos_;
293             break;
294         }
295         if (ret != E_OK) {
296             LOG_ERROR("Get row cnt err %{public}d, rowCount_ %{public}d, rowPos_ %{public}d", ret, rowCount_, rowPos_);
297             return ret;
298         }
299     };
300     count = rowCount_;
301     // Reset the start position of the query result
302     if (oldPosition != INIT_POS) {
303         GoToRow(oldPosition);
304     } else {
305         Reset();
306     }
307     return E_OK;
308 }
309 
310 /**
311  * Reset the statement
312  */
Reset()313 int StepResultSet::Reset()
314 {
315     rowPos_ = INIT_POS;
316     auto statement = GetStatement();
317     if (statement != nullptr) {
318         return statement->Reset();
319     }
320     return E_OK;
321 }
322 
Get(int32_t col,ValueObject & value)323 int StepResultSet::Get(int32_t col, ValueObject &value)
324 {
325     if (isClosed_) {
326         return E_ALREADY_CLOSED;
327     }
328     return GetValue(col, value);
329 }
330 
GetSize(int columnIndex,size_t & size)331 int StepResultSet::GetSize(int columnIndex, size_t &size)
332 {
333     if (isClosed_) {
334         return E_ALREADY_CLOSED;
335     }
336     if (rowPos_ == INIT_POS || ((isSupportCountRow_ || rowCount_ != Statement::INVALID_COUNT) && IsEnded().second)) {
337         size = 0;
338         return E_ROW_OUT_RANGE;
339     }
340 
341     auto statement = GetStatement();
342     if (statement == nullptr) {
343         LOG_ERROR("Statement is nullptr.");
344         return E_ALREADY_CLOSED;
345     }
346     auto errCode = E_ERROR;
347     std::tie(errCode, size) = statement->GetSize(columnIndex);
348     return errCode;
349 }
350 
351 template<typename T>
GetValue(int32_t col,T & value)352 int StepResultSet::GetValue(int32_t col, T &value)
353 {
354     auto [errCode, object] = GetValueObject(col, ValueObject::TYPE_INDEX<decltype(value)>);
355     if (errCode != E_OK) {
356         LOG_ERROR("ret is %{public}d", errCode);
357         return errCode;
358     }
359     value = static_cast<T>(object);
360     return E_OK;
361 }
362 
GetValueObject(int32_t col,size_t index)363 std::pair<int, ValueObject> StepResultSet::GetValueObject(int32_t col, size_t index)
364 {
365     if (rowPos_ == INIT_POS || ((isSupportCountRow_ || rowCount_ != Statement::INVALID_COUNT) && IsEnded().second)) {
366         return { E_ROW_OUT_RANGE, ValueObject() };
367     }
368     auto statement = GetStatement();
369     if (statement == nullptr) {
370         return { E_ALREADY_CLOSED, ValueObject() };
371     }
372     auto [ret, value] = statement->GetColumn(col);
373     if (index < ValueObject::TYPE_MAX && value.value.index() != index) {
374         return { E_INVALID_COLUMN_TYPE, ValueObject() };
375     }
376     return { ret, std::move(value) };
377 }
378 
GetStatement()379 std::shared_ptr<Statement> StepResultSet::GetStatement()
380 {
381     std::lock_guard<decltype(globalMtx_)> lockGuard(globalMtx_);
382     if (isClosed_ || conn_ == nullptr) {
383         return nullptr;
384     }
385 
386     return statement_;
387 }
388 } // namespace NativeRdb
389 } // namespace OHOS
390