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
16 #include "step_result_set.h"
17
18 #include <unistd.h>
19
20 #include "logger.h"
21 #include "rdb_errno.h"
22 #include "rdb_trace.h"
23 #include "sqlite3sym.h"
24 #include "rdb_sql_utils.h"
25 #include "sqlite_errno.h"
26 #include "sqlite_utils.h"
27
28 namespace OHOS {
29 namespace NativeRdb {
30 using namespace OHOS::Rdb;
31
StepResultSet(std::shared_ptr<RdbStoreImpl> rdb,SqliteConnectionPool * connectionPool,const std::string & sql,const std::vector<ValueObject> & selectionArgs)32 StepResultSet::StepResultSet(std::shared_ptr<RdbStoreImpl> rdb, SqliteConnectionPool *connectionPool,
33 const std::string &sql, const std::vector<ValueObject> &selectionArgs)
34 : rdb(rdb), connectionPool_(connectionPool), sql(sql), args_(std::move(selectionArgs)), isAfterLast(false),
35 rowCount(INIT_POS), sqliteStatement(nullptr), connection_(connectionPool_->AcquireConnection(true))
36 {
37 }
38
~StepResultSet()39 StepResultSet::~StepResultSet()
40 {
41 Close();
42 rdb.reset();
43 }
44
GetAllColumnNames(std::vector<std::string> & columnNames)45 int StepResultSet::GetAllColumnNames(std::vector<std::string> &columnNames)
46 {
47 if (!columnNames_.empty()) {
48 columnNames = columnNames_;
49 return E_OK;
50 }
51
52 if (isClosed) {
53 LOG_ERROR("resultSet closed");
54 return E_STEP_RESULT_CLOSED;
55 }
56
57 int errCode = PrepareStep();
58 if (errCode) {
59 LOG_ERROR("PrepareStep ret %{public}d", errCode);
60 return errCode;
61 }
62
63 int columnCount = 0;
64 errCode = sqliteStatement->GetColumnCount(columnCount);
65 if (errCode) {
66 LOG_ERROR("GetColumnCount ret %{public}d", errCode);
67 return errCode;
68 }
69
70 columnNames.clear();
71 for (int i = 0; i < columnCount; i++) {
72 std::string columnName;
73 errCode = sqliteStatement->GetColumnName(i, columnName);
74 if (errCode) {
75 columnNames.clear();
76 LOG_ERROR("GetColumnName ret %{public}d", errCode);
77 return errCode;
78 }
79 columnNames.push_back(columnName);
80 }
81
82 return E_OK;
83 }
84
GetColumnType(int columnIndex,ColumnType & columnType)85 int StepResultSet::GetColumnType(int columnIndex, ColumnType &columnType)
86 {
87 if (isClosed) {
88 LOG_ERROR("resultSet closed");
89 return E_STEP_RESULT_CLOSED;
90 }
91
92 if (rowPos_ == INIT_POS) {
93 LOG_ERROR("query not executed.");
94 return E_STEP_RESULT_QUERY_NOT_EXECUTED;
95 }
96 int sqliteType;
97 int errCode = sqliteStatement->GetColumnType(columnIndex, sqliteType);
98 if (errCode) {
99 LOG_ERROR("GetColumnType ret %{public}d", errCode);
100 return errCode;
101 }
102
103 switch (sqliteType) {
104 case SQLITE_INTEGER:
105 columnType = ColumnType::TYPE_INTEGER;
106 break;
107 case SQLITE_FLOAT:
108 columnType = ColumnType::TYPE_FLOAT;
109 break;
110 case SQLITE_BLOB:
111 columnType = ColumnType::TYPE_BLOB;
112 break;
113 case SQLITE_NULL:
114 columnType = ColumnType::TYPE_NULL;
115 break;
116 default:
117 columnType = ColumnType::TYPE_STRING;
118 }
119
120 return E_OK;
121 }
122
GetRowCount(int & count)123 int StepResultSet::GetRowCount(int &count)
124 {
125 if (rowCount != INIT_POS) {
126 count = rowCount;
127 return E_OK;
128 }
129 int oldPosition = 0;
130 // Get the start position of the query result
131 GetRowIndex(oldPosition);
132
133 while (GoToNextRow() == E_OK) {
134 }
135 count = rowCount;
136 // Reset the start position of the query result
137 GoToRow(oldPosition);
138
139 return E_OK;
140 }
141
142 /**
143 * Moves the result set to a specified position
144 */
GoToRow(int position)145 int StepResultSet::GoToRow(int position)
146 {
147 if (connection_ == nullptr) {
148 LOG_ERROR("Failed as too many connections");
149 return E_CON_OVER_LIMIT;
150 }
151 // If the moved position is less than zero, reset the result and return an error
152 if (position < 0) {
153 LOG_DEBUG("position %{public}d.", position);
154 Reset();
155 return E_ERROR;
156 }
157 if (position == rowPos_) {
158 return E_OK;
159 }
160 if (position < rowPos_) {
161 Reset();
162 return GoToRow(position);
163 }
164 while (position != rowPos_) {
165 int errCode = GoToNextRow();
166 if (errCode) {
167 LOG_ERROR("GoToNextRow ret %{public}d", errCode);
168 return errCode;
169 }
170 }
171
172 return E_OK;
173 }
174
175 /**
176 * Move the result set to the next row
177 */
GoToNextRow()178 int StepResultSet::GoToNextRow()
179 {
180 if (isClosed) {
181 LOG_ERROR("resultSet closed");
182 return E_STEP_RESULT_CLOSED;
183 }
184
185 int errCode = PrepareStep();
186 if (errCode) {
187 LOG_ERROR("PrepareStep ret %{public}d", errCode);
188 return errCode;
189 }
190
191 int retryCount = 0;
192 errCode = sqliteStatement->Step();
193
194 while (errCode == SQLITE_LOCKED || errCode == SQLITE_BUSY) {
195 // The table is locked, retry
196 if (retryCount > STEP_QUERY_RETRY_MAX_TIMES) {
197 LOG_ERROR("Step in busy ret is %{public}d", errCode);
198 return E_STEP_RESULT_QUERY_EXCEEDED;
199 } else {
200 // Sleep to give the thread holding the lock a chance to finish
201 usleep(STEP_QUERY_RETRY_INTERVAL);
202 errCode = sqliteStatement->Step();
203 retryCount++;
204 }
205 }
206
207 if (errCode == SQLITE_ROW) {
208 rowPos_++;
209 return E_OK;
210 } else if (errCode == SQLITE_DONE) {
211 isAfterLast = true;
212 rowCount = rowPos_ + 1;
213 FinishStep();
214 rowPos_ = rowCount;
215 return E_STEP_RESULT_IS_AFTER_LAST;
216 } else {
217 LOG_ERROR("step ret is %{public}d", errCode);
218 FinishStep();
219 rowPos_ = rowCount;
220 return SQLiteError::ErrNo(errCode);
221 }
222 }
223
Close()224 int StepResultSet::Close()
225 {
226 if (isClosed) {
227 return E_OK;
228 }
229 isClosed = true;
230 int errCode = FinishStep();
231
232 connectionPool_->ReleaseConnection(connection_);
233 connection_ = nullptr;
234 return errCode;
235 }
236
237 /**
238 * Obtain session and prepare precompile statement for step query
239 */
PrepareStep()240 int StepResultSet::PrepareStep()
241 {
242 if (sqliteStatement != nullptr) {
243 return E_OK;
244 }
245
246 if (connection_ == nullptr) {
247 LOG_ERROR("too many connections");
248 return E_CON_OVER_LIMIT;
249 }
250
251 if (SqliteUtils::GetSqlStatementType(sql) != SqliteUtils::STATEMENT_SELECT) {
252 LOG_ERROR("not a select sql!");
253 return E_EXECUTE_IN_STEP_QUERY;
254 }
255
256 int errCode;
257 sqliteStatement = connection_->BeginStepQuery(errCode, sql, args_);
258 if (sqliteStatement == nullptr) {
259 connection_->EndStepQuery();
260 LOG_ERROR("BeginStepQuery ret is %{public}d", errCode);
261 return errCode;
262 }
263
264 return E_OK;
265 }
266
267 /**
268 * Release resource of step result set, this method can be called more than once
269 */
FinishStep()270 int StepResultSet::FinishStep()
271 {
272 if (sqliteStatement == nullptr) {
273 return E_OK;
274 }
275
276 sqliteStatement = nullptr;
277 rowPos_ = INIT_POS;
278 if (connection_ == nullptr) {
279 return E_OK;
280 }
281
282 int errCode = connection_->EndStepQuery();
283 if (errCode != E_OK) {
284 LOG_ERROR("ret is %d", errCode);
285 }
286 return errCode;
287 }
288
289 /**
290 * Reset the statement
291 */
Reset()292 void StepResultSet::Reset()
293 {
294 if (sqliteStatement != nullptr) {
295 sqlite3_reset(sqliteStatement->GetSql3Stmt());
296 }
297 rowPos_ = INIT_POS;
298 isAfterLast = false;
299 }
300
301
302 /**
303 * Checks whether the result set is positioned after the last row
304 */
IsEnded(bool & result)305 int StepResultSet::IsEnded(bool &result)
306 {
307 result = isAfterLast;
308 return E_OK;
309 }
310
311 /**
312 * Checks whether the result set is moved
313 */
IsStarted(bool & result) const314 int StepResultSet::IsStarted(bool &result) const
315 {
316 result = (rowPos_ != INIT_POS);
317 return E_OK;
318 }
319
320 /**
321 * Check whether the result set is in the first row
322 */
IsAtFirstRow(bool & result) const323 int StepResultSet::IsAtFirstRow(bool &result) const
324 {
325 result = (rowPos_ == 0);
326 return E_OK;
327 }
328
GetBlob(int columnIndex,std::vector<uint8_t> & blob)329 int StepResultSet::GetBlob(int columnIndex, std::vector<uint8_t> &blob)
330 {
331 if (isClosed) {
332 return E_STEP_RESULT_CLOSED;
333 }
334 if (rowPos_ == INIT_POS) {
335 LOG_ERROR("query not executed.");
336 return E_STEP_RESULT_QUERY_NOT_EXECUTED;
337 }
338
339 return sqliteStatement->GetColumnBlob(columnIndex, blob);
340 }
341
GetString(int columnIndex,std::string & value)342 int StepResultSet::GetString(int columnIndex, std::string &value)
343 {
344 if (isClosed) {
345 return E_STEP_RESULT_CLOSED;
346 }
347
348 if (rowPos_ == INIT_POS) {
349 return E_STEP_RESULT_QUERY_NOT_EXECUTED;
350 }
351
352 int errCode = sqliteStatement->GetColumnString(columnIndex, value);
353 if (errCode != E_OK) {
354 LOG_ERROR("ret is %{public}d", errCode);
355 return errCode;
356 }
357 return E_OK;
358 }
359
GetInt(int columnIndex,int & value)360 int StepResultSet::GetInt(int columnIndex, int &value)
361 {
362 if (isClosed) {
363 return E_STEP_RESULT_CLOSED;
364 }
365 if (rowPos_ == INIT_POS) {
366 return E_STEP_RESULT_QUERY_NOT_EXECUTED;
367 }
368
369 int64_t columnValue;
370 int errCode = sqliteStatement->GetColumnLong(columnIndex, columnValue);
371 if (errCode != E_OK) {
372 LOG_ERROR("ret is %{public}d", errCode);
373 return errCode;
374 }
375 value = static_cast<int>(columnValue);
376 return E_OK;
377 }
378
GetLong(int columnIndex,int64_t & value)379 int StepResultSet::GetLong(int columnIndex, int64_t &value)
380 {
381 if (isClosed) {
382 return E_STEP_RESULT_CLOSED;
383 }
384 if (rowPos_ == INIT_POS) {
385 return E_STEP_RESULT_QUERY_NOT_EXECUTED;
386 }
387 int errCode = sqliteStatement->GetColumnLong(columnIndex, value);
388 if (errCode != E_OK) {
389 LOG_ERROR("ret is %{public}d", errCode);
390 return errCode;
391 }
392 return E_OK;
393 }
394
GetDouble(int columnIndex,double & value)395 int StepResultSet::GetDouble(int columnIndex, double &value)
396 {
397 if (isClosed) {
398 return E_STEP_RESULT_CLOSED;
399 }
400 if (rowPos_ == INIT_POS) {
401 return E_STEP_RESULT_QUERY_NOT_EXECUTED;
402 }
403 int errCode = sqliteStatement->GetColumnDouble(columnIndex, value);
404 if (errCode != E_OK) {
405 LOG_ERROR("ret is %{public}d", errCode);
406 return errCode;
407 }
408 return E_OK;
409 }
410
GetAsset(int32_t col,ValueObject::Asset & value)411 int StepResultSet::GetAsset(int32_t col, ValueObject::Asset &value)
412 {
413 return GetValue(col, value);
414 }
415
GetAssets(int32_t col,ValueObject::Assets & value)416 int StepResultSet::GetAssets(int32_t col, ValueObject::Assets &value)
417 {
418 return GetValue(col, value);
419 }
420
Get(int32_t col,ValueObject & value)421 int StepResultSet::Get(int32_t col, ValueObject &value)
422 {
423 return GetValue(col, value);
424 }
425
GetModifyTime(std::string & modifyTime)426 int StepResultSet::GetModifyTime(std::string &modifyTime)
427 {
428 if (isClosed) {
429 return E_STEP_RESULT_CLOSED;
430 }
431 if (rowPos_ == INIT_POS) {
432 return E_STEP_RESULT_QUERY_NOT_EXECUTED;
433 }
434 auto index = std::find(columnNames_.begin(), columnNames_.end(), "modifyTime");
435 int errCode = sqliteStatement->GetColumnString(index - columnNames_.begin(), modifyTime);
436 if (errCode != E_OK) {
437 LOG_ERROR("ret is %{public}d", errCode);
438 return errCode;
439 }
440 return E_OK;
441 }
442
GetSize(int columnIndex,size_t & size)443 int StepResultSet::GetSize(int columnIndex, size_t &size)
444 {
445 if (rowPos_ == INIT_POS) {
446 size = 0;
447 return E_STEP_RESULT_QUERY_NOT_EXECUTED;
448 }
449
450 return sqliteStatement->GetSize(columnIndex, size);
451 }
452
IsColumnNull(int columnIndex,bool & isNull)453 int StepResultSet::IsColumnNull(int columnIndex, bool &isNull)
454 {
455 ColumnType columnType;
456 int errCode = GetColumnType(columnIndex, columnType);
457 if (errCode != E_OK) {
458 LOG_ERROR("ret is %{public}d", errCode);
459 return errCode;
460 }
461 isNull = (columnType == ColumnType::TYPE_NULL);
462 return E_OK;
463 }
464
465 /**
466 * Check whether the result set is over
467 */
IsClosed() const468 bool StepResultSet::IsClosed() const
469 {
470 return isClosed;
471 }
472
473 template<typename T>
GetValue(int32_t col,T & value)474 int StepResultSet::GetValue(int32_t col, T &value)
475 {
476 auto [errCode, object] = GetValueObject(col, ValueObject::TYPE_INDEX<decltype(value)>);
477 if (errCode != E_OK) {
478 LOG_ERROR("ret is %{public}d", errCode);
479 return errCode;
480 }
481 value = object;
482 return E_OK;
483 }
484
GetValueObject(int32_t col,size_t index)485 std::pair<int, ValueObject> StepResultSet::GetValueObject(int32_t col, size_t index)
486 {
487 if (isClosed) {
488 return { E_STEP_RESULT_CLOSED, ValueObject() };
489 }
490
491 if (rowPos_ == INIT_POS) {
492 return { E_STEP_RESULT_QUERY_NOT_EXECUTED, ValueObject() };
493 }
494
495 ValueObject value;
496 auto ret = sqliteStatement->GetColumn(col, value);
497 if (index < ValueObject::TYPE_MAX && value.value.index() != index) {
498 return { E_INVALID_COLUMN_TYPE, ValueObject() };
499 }
500 return { ret, std::move(value) };
501 }
502 } // namespace NativeRdb
503 } // namespace OHOS