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