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