• 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 
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