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 #define LOG_TAG "StepResultSet"
17
18 #include "step_result_set.h"
19
20 #include <unistd.h>
21
22 #include "logger.h"
23 #include "rdb_errno.h"
24 #include "rdb_trace.h"
25 #include "sqlite3sym.h"
26 #include "sqlite_errno.h"
27
28 namespace OHOS {
29 namespace NativeRdb {
StepResultSet(std::shared_ptr<RdbStoreImpl> rdb,const std::string & sql,const std::vector<std::string> & selectionArgs)30 StepResultSet::StepResultSet(
31 std::shared_ptr<RdbStoreImpl> rdb, const std::string &sql, const std::vector<std::string> &selectionArgs)
32 : rdb(rdb), sql(sql), selectionArgs(selectionArgs), isAfterLast(false), rowCount(INIT_POS),
33 sqliteStatement(nullptr)
34 {
35 }
36
~StepResultSet()37 StepResultSet::~StepResultSet()
38 {
39 Close();
40 }
41
GetAllColumnNames(std::vector<std::string> & columnNames)42 int StepResultSet::GetAllColumnNames(std::vector<std::string> &columnNames)
43 {
44 bool needRelease = false;
45 if (sqliteStatement == nullptr) {
46 int errCode = E_STEP_RESULT_QUERY_NOT_EXECUTED;
47 sqliteStatement = rdb->BeginStepQuery(errCode, sql, selectionArgs);
48 if (sqliteStatement == nullptr) {
49 return errCode;
50 }
51 needRelease = true;
52 }
53
54 int columnCount = 0;
55 auto errCode = sqliteStatement->GetColumnCount(columnCount);
56 if (errCode) {
57 return errCode;
58 }
59
60 columnNames.clear();
61 for (int i = 0; i < columnCount; i++) {
62 std::string columnName;
63 errCode = sqliteStatement->GetColumnName(i, columnName);
64 if (errCode) {
65 columnNames.clear();
66 return errCode;
67 }
68 columnNames.push_back(columnName);
69 columnMap_[columnName] = i;
70 }
71 if (needRelease) {
72 rdb->EndStepQuery();
73 sqliteStatement = nullptr;
74 }
75 return E_OK;
76 }
77
GetColumnType(int columnIndex,ColumnType & columnType)78 int StepResultSet::GetColumnType(int columnIndex, ColumnType &columnType)
79 {
80 if (rowPos_ == INIT_POS) {
81 return E_STEP_RESULT_QUERY_NOT_EXECUTED;
82 }
83 int sqliteType;
84 int errCode = sqliteStatement->GetColumnType(columnIndex, sqliteType);
85 if (errCode) {
86 return errCode;
87 }
88
89 switch (sqliteType) {
90 case SQLITE_INTEGER:
91 columnType = ColumnType::TYPE_INTEGER;
92 break;
93 case SQLITE_FLOAT:
94 columnType = ColumnType::TYPE_FLOAT;
95 break;
96 case SQLITE_BLOB:
97 columnType = ColumnType::TYPE_BLOB;
98 break;
99 case SQLITE_NULL:
100 columnType = ColumnType::TYPE_NULL;
101 break;
102 default:
103 columnType = ColumnType::TYPE_STRING;
104 }
105
106 return E_OK;
107 }
108
GetRowCount(int & count)109 int StepResultSet::GetRowCount(int &count)
110 {
111 if (rowCount != INIT_POS) {
112 count = rowCount;
113 return E_OK;
114 }
115 int oldPosition = 0;
116 // Get the start position of the query result
117 GetRowIndex(oldPosition);
118
119 while (GoToNextRow() == E_OK) {
120 }
121 count = rowCount;
122 // Reset the start position of the query result
123 GoToRow(oldPosition);
124
125 return E_OK;
126 }
127
128 /**
129 * Moves the result set to a specified position
130 */
GoToRow(int position)131 int StepResultSet::GoToRow(int position)
132 {
133 if (!rdb) {
134 return E_ERROR;
135 }
136 // If the moved position is less than zero, reset the result and return an error
137 if (position < 0) {
138 Reset();
139 return E_ERROR;
140 }
141 if (position == rowPos_) {
142 return E_OK;
143 }
144 if (position < rowPos_) {
145 Reset();
146 return GoToRow(position);
147 }
148 while (position != rowPos_) {
149 int errCode = GoToNextRow();
150 if (errCode) {
151 return errCode;
152 }
153 }
154
155 return E_OK;
156 }
157
158 /**
159 * Move the result set to the next row
160 */
GoToNextRow()161 int StepResultSet::GoToNextRow()
162 {
163 int errCode = PrepareStep();
164 if (errCode) {
165 return errCode;
166 }
167
168 int retryCount = 0;
169 errCode = sqliteStatement->Step();
170
171 while (errCode == SQLITE_LOCKED || errCode == SQLITE_BUSY) {
172 // The table is locked, retry
173 if (retryCount > STEP_QUERY_RETRY_MAX_TIMES) {
174 LOG_ERROR("StepResultSet::GoToNextRow retrycount exceeded");
175 return E_STEP_RESULT_QUERY_EXCEEDED;
176 } else {
177 // Sleep to give the thread holding the lock a chance to finish
178 usleep(STEP_QUERY_RETRY_INTERVAL);
179 errCode = sqliteStatement->Step();
180 retryCount++;
181 }
182 }
183
184 if (errCode == SQLITE_ROW) {
185 rowPos_++;
186 return E_OK;
187 } else if (errCode == SQLITE_DONE) {
188 isAfterLast = true;
189 rowCount = rowPos_ + 1;
190 FinishStep();
191 return E_STEP_RESULT_IS_AFTER_LAST;
192 } else {
193 LOG_ERROR("StepResultSet::GoToNextRow step err = %{public}d", errCode);
194 FinishStep();
195 return SQLiteError::ErrNo(errCode);
196 }
197 }
198
199 /**
200 * Checks whether the result set is positioned after the last row
201 */
IsEnded(bool & result)202 int StepResultSet::IsEnded(bool &result)
203 {
204 result = isAfterLast;
205 return E_OK;
206 }
207
208 /**
209 * Checks whether the result set is moved
210 */
IsStarted(bool & result) const211 int StepResultSet::IsStarted(bool &result) const
212 {
213 result = (rowPos_ != INIT_POS);
214 return E_OK;
215 }
216
217 /**
218 * Check whether the result set is in the first row
219 */
IsAtFirstRow(bool & result) const220 int StepResultSet::IsAtFirstRow(bool &result) const
221 {
222 result = (rowPos_ == 0);
223 return E_OK;
224 }
225
GetBlob(int columnIndex,std::vector<uint8_t> & blob)226 int StepResultSet::GetBlob(int columnIndex, std::vector<uint8_t> &blob)
227 {
228 if (rowPos_ == INIT_POS) {
229 return E_STEP_RESULT_QUERY_NOT_EXECUTED;
230 }
231
232 return sqliteStatement->GetColumnBlob(columnIndex, blob);
233 }
234
GetString(int columnIndex,std::string & value)235 int StepResultSet::GetString(int columnIndex, std::string &value)
236 {
237 DISTRIBUTED_DATA_HITRACE("StepResultSet::GetString");
238 if (rowPos_ == INIT_POS) {
239 return E_STEP_RESULT_QUERY_NOT_EXECUTED;
240 }
241
242 int errCode = sqliteStatement->GetColumnString(columnIndex, value);
243 if (errCode != E_OK) {
244 LOG_ERROR("StepResultSet::GetString is err=%{public}d", errCode);
245 return errCode;
246 }
247 return E_OK;
248 }
249
GetInt(int columnIndex,int & value)250 int StepResultSet::GetInt(int columnIndex, int &value)
251 {
252 if (rowPos_ == INIT_POS) {
253 return E_STEP_RESULT_QUERY_NOT_EXECUTED;
254 }
255
256 int64_t columnValue;
257 int errCode = sqliteStatement->GetColumnLong(columnIndex, columnValue);
258 if (errCode != E_OK) {
259 return errCode;
260 }
261 value = static_cast<int>(columnValue);
262 return E_OK;
263 }
264
GetLong(int columnIndex,int64_t & value)265 int StepResultSet::GetLong(int columnIndex, int64_t &value)
266 {
267 if (rowPos_ == INIT_POS) {
268 return E_STEP_RESULT_QUERY_NOT_EXECUTED;
269 }
270 int errCode = sqliteStatement->GetColumnLong(columnIndex, value);
271 if (errCode != E_OK) {
272 return errCode;
273 }
274 return E_OK;
275 }
276
GetDouble(int columnIndex,double & value)277 int StepResultSet::GetDouble(int columnIndex, double &value)
278 {
279 if (rowPos_ == INIT_POS) {
280 return E_STEP_RESULT_QUERY_NOT_EXECUTED;
281 }
282 int errCode = sqliteStatement->GetColumnDouble(columnIndex, value);
283 if (errCode != E_OK) {
284 return errCode;
285 }
286 return E_OK;
287 }
288
IsColumnNull(int columnIndex,bool & isNull)289 int StepResultSet::IsColumnNull(int columnIndex, bool &isNull)
290 {
291 ColumnType columnType;
292 int errCode = GetColumnType(columnIndex, columnType);
293 if (errCode != E_OK) {
294 return errCode;
295 }
296 isNull = (columnType == ColumnType::TYPE_NULL);
297 return E_OK;
298 }
299
300 /**
301 * Check whether the result set is over
302 */
IsClosed() const303 bool StepResultSet::IsClosed() const
304 {
305 return isClosed;
306 }
307
Close()308 int StepResultSet::Close()
309 {
310 if (isClosed) {
311 return E_OK;
312 }
313 isClosed = true;
314 int errCode = FinishStep();
315 rdb = nullptr;
316 return errCode;
317 }
318
CheckSession()319 int StepResultSet::CheckSession()
320 {
321 if (std::this_thread::get_id() != tid) {
322 LOG_ERROR("StepResultSet is passed cross threads!");
323 return E_STEP_RESULT_SET_CROSS_THREADS;
324 }
325 return E_OK;
326 }
327
328 /**
329 * Obtain session and prepare precompile statement for step query
330 */
PrepareStep()331 int StepResultSet::PrepareStep()
332 {
333 LOG_DEBUG("begin");
334 if (isClosed) {
335 return E_STEP_RESULT_CLOSED;
336 }
337
338 if (sqliteStatement != nullptr) {
339 return CheckSession();
340 }
341
342 int errCode;
343 LOG_DEBUG("rdb->BeginStepQuery begin");
344 sqliteStatement = rdb->BeginStepQuery(errCode, sql, selectionArgs);
345 if (sqliteStatement == nullptr) {
346 rdb->EndStepQuery();
347 return errCode;
348 }
349
350 LOG_DEBUG("get_id begin");
351 tid = std::this_thread::get_id();
352 return E_OK;
353 }
354
355 /**
356 * Release resource of step result set, this method can be called more than once
357 */
FinishStep()358 int StepResultSet::FinishStep()
359 {
360 if (sqliteStatement == nullptr) {
361 return E_OK;
362 }
363
364 int errCode = CheckSession();
365 if (errCode != E_OK) {
366 return errCode;
367 }
368
369 sqliteStatement = nullptr;
370 rowPos_ = INIT_POS;
371 if (rdb != nullptr) {
372 errCode = rdb->EndStepQuery();
373 }
374 if (errCode != E_OK) {
375 LOG_ERROR("StepResultSet::FinishStep err = %{public}d", errCode);
376 }
377 return errCode;
378 }
379
380 /**
381 * Reset the statement
382 */
Reset()383 void StepResultSet::Reset()
384 {
385 if (sqliteStatement != nullptr) {
386 sqlite3_reset(sqliteStatement->GetSql3Stmt());
387 }
388 rowPos_ = INIT_POS;
389 isAfterLast = false;
390 }
391 } // namespace NativeRdb
392 } // namespace OHOS