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 "trace_data_db.h"
17 #include <chrono>
18 #include <cmath>
19 #include <cstdio>
20 #include <cstring>
21 #include <fcntl.h>
22 #include <functional>
23 #include <string_view>
24 #include <unistd.h>
25 #include <regex>
26
27 #include "codec_cov.h"
28 #include "file.h"
29 #include "log.h"
30 #include "sph_data.pb.h"
31 #include "sqlite3.h"
32 #include "sqlite_ext/sqlite_ext_funcs.h"
33 #include "string_help.h"
34 #include "ts_common.h"
35
36 namespace SysTuning {
37 namespace TraceStreamer {
38 const int32_t ONCE_MAX_MB = 1024 * 1024 * 4;
39 constexpr int32_t DEFAULT_LEN_ROW_STRING = 1024;
40
41 enum class DBFiledType : uint8_t { INT = 0, TEXT };
42 using namespace SysTuning::base;
43
TraceDataDB()44 TraceDataDB::TraceDataDB() : db_(nullptr)
45 {
46 if (sqlite3_threadsafe() > 0) {
47 int32_t retCode = sqlite3_config(SQLITE_CONFIG_SERIALIZED);
48 if (retCode == SQLITE_OK) {
49 TS_LOGI("Can now use sqlite on multiple threads, using the same connection");
50 } else {
51 TS_LOGE("setting sqlite thread safe mode to serialized failed!!! return code: %d", retCode);
52 }
53 } else {
54 TS_LOGE("Your SQLite database is not compiled to be threadsafe.");
55 }
56 if (sqlite3_open(":memory:", &db_)) {
57 TS_LOGF("open :memory db failed");
58 }
59 ts_create_extend_function(db_);
60 }
61
~TraceDataDB()62 TraceDataDB::~TraceDataDB()
63 {
64 sqlite3_close(db_);
65 }
66
AppendNewTable(std::string tableName)67 void TraceDataDB::AppendNewTable(std::string tableName)
68 {
69 internalTables_.push_back(tableName);
70 }
EnableMetaTable(bool enabled)71 void TraceDataDB::EnableMetaTable(bool enabled)
72 {
73 exportMetaTable_ = enabled;
74 }
75
SendDatabase(ResultCallBack resultCallBack)76 void TraceDataDB::SendDatabase(ResultCallBack resultCallBack)
77 {
78 int32_t fd(base::OpenFile(wasmDBName_, O_RDWR, TS_PERMISSION_RW));
79 if (!fd) {
80 TS_LOGD("Failed to open file: %s", wasmDBName_.c_str());
81 return;
82 }
83
84 while (true) {
85 uint8_t data[DATABASE_BASE];
86 auto size = base::Read(fd, data, DATABASE_BASE);
87 if (size == 0) {
88 resultCallBack(std::string((char*)data, size), SEND_FINISH);
89 break;
90 } else if (size < 0) {
91 TS_LOGD("Reading trace file failed (errno: %d, %s)", errno, strerror(errno));
92 break;
93 }
94 resultCallBack(std::string((char*)data, DATABASE_BASE), SEND_CONTINUE);
95 }
96 close(fd);
97 (void)remove(wasmDBName_.c_str());
98 wasmDBName_.clear();
99 }
CreatEmptyBatchDB(const std::string & outputName)100 int32_t TraceDataDB::CreatEmptyBatchDB(const std::string& outputName)
101 {
102 {
103 int32_t fd(base::OpenFile(outputName, O_CREAT | O_RDWR, TS_PERMISSION_RW));
104 if (!fd) {
105 fprintf(stdout, "Failed to create file: %s", outputName.c_str());
106 return 1;
107 }
108 auto ret = ftruncate(fd, 0);
109 Unused(ret);
110 close(fd);
111 }
112 std::string attachSql("ATTACH DATABASE '" + outputName + "' AS systuning_export");
113 #ifdef _WIN32
114 if (!base::GetCoding(reinterpret_cast<const uint8_t*>(attachSql.c_str()), attachSql.length())) {
115 attachSql = base::GbkToUtf8(attachSql.c_str());
116 }
117 #endif
118 ExecuteSql(attachSql);
119 for (auto itor = internalTables_.begin(); itor != internalTables_.end(); itor++) {
120 if (*itor == "meta" && !exportMetaTable_) {
121 continue;
122 } else {
123 std::string exportSql("CREATE TABLE systuning_export." + (*itor) + "_ AS SELECT * FROM " + *itor);
124 ExecuteSql(exportSql);
125 }
126 }
127 std::string detachSql("DETACH DATABASE systuning_export");
128 ExecuteSql(detachSql);
129 return 0;
130 }
CloseBatchDB()131 void TraceDataDB::CloseBatchDB()
132 {
133 std::string detachSql("DETACH DATABASE systuning_export");
134 ExecuteSql(detachSql);
135 }
BatchExportDatabase(const std::string & outputName)136 int32_t TraceDataDB::BatchExportDatabase(const std::string& outputName)
137 {
138 std::string attachSql("ATTACH DATABASE '" + outputName + "' AS systuning_export");
139 #ifdef _WIN32
140 if (!base::GetCoding(reinterpret_cast<const uint8_t*>(attachSql.c_str()), attachSql.length())) {
141 attachSql = base::GbkToUtf8(attachSql.c_str());
142 }
143 #endif
144 ExecuteSql(attachSql);
145 for (auto itor = internalTables_.begin(); itor != internalTables_.end(); itor++) {
146 if (*itor == "meta" && !exportMetaTable_) {
147 continue;
148 } else {
149 if (needClearTable_.count(*itor)) {
150 std::string clearSql("DELETE FROM systuning_export." + (*itor) + "_");
151 ExecuteSql(clearSql);
152 }
153 std::string exportSql("INSERT INTO systuning_export." + (*itor) + "_ SELECT * FROM " + *itor);
154 ExecuteSql(exportSql);
155 }
156 }
157 std::string createArgsView =
158 "create view systuning_export.args_view AS select A.argset, V2.data as keyName, A.id, D.desc, (case when "
159 "A.datatype==1 then V.data else A.value end) as strValue from args_ as A left join data_type_ as D on "
160 "(D.typeId "
161 "= A.datatype) left join data_dict_ as V on V.id = A.value left join data_dict_ as V2 on V2.id = A.key";
162 ExecuteSql(createArgsView);
163 std::string updateProcessName =
164 "update process set name = (select name from thread t where t.ipid = process.id and t.name is not null and "
165 "is_main_thread = 1)";
166 ExecuteSql(updateProcessName);
167 std::string detachSql("DETACH DATABASE systuning_export");
168 ExecuteSql(detachSql);
169 return 0;
170 }
RevertTableName(const std::string & outputName)171 void TraceDataDB::RevertTableName(const std::string& outputName)
172 {
173 std::string attachSql("ATTACH DATABASE '" + outputName + "' AS systuning_export");
174 #ifdef _WIN32
175 if (!base::GetCoding(reinterpret_cast<const uint8_t*>(attachSql.c_str()), attachSql.length())) {
176 attachSql = base::GbkToUtf8(attachSql.c_str());
177 }
178 #endif
179 ExecuteSql(attachSql);
180 for (auto itor = internalTables_.begin(); itor != internalTables_.end(); itor++) {
181 if (*itor == "meta" && !exportMetaTable_) {
182 continue;
183 } else {
184 std::string revertTableNameSql("ALTER TABLE systuning_export." + (*itor) + "_ RENAME TO " + (*itor));
185 ExecuteSql(revertTableNameSql);
186 }
187 }
188 std::string detachSql("DETACH DATABASE systuning_export");
189 ExecuteSql(detachSql);
190 }
ExportDatabase(const std::string & outputName,ResultCallBack resultCallBack)191 int32_t TraceDataDB::ExportDatabase(const std::string& outputName, ResultCallBack resultCallBack)
192 {
193 {
194 int32_t fd(base::OpenFile(outputName, O_CREAT | O_RDWR, TS_PERMISSION_RW));
195 if (!fd) {
196 fprintf(stdout, "Failed to create file: %s", outputName.c_str());
197 return 1;
198 }
199 auto ret = ftruncate(fd, 0);
200 Unused(ret);
201 close(fd);
202 }
203
204 std::string attachSql("ATTACH DATABASE '" + outputName + "' AS systuning_export");
205 #ifdef _WIN32
206 if (!base::GetCoding(reinterpret_cast<const uint8_t*>(attachSql.c_str()), attachSql.length())) {
207 attachSql = base::GbkToUtf8(attachSql.c_str());
208 }
209 #endif
210 ExecuteSql(attachSql);
211
212 for (auto itor = internalTables_.begin(); itor != internalTables_.end(); itor++) {
213 if (*itor == "meta" && !exportMetaTable_) {
214 continue;
215 } else {
216 std::string exportSql("CREATE TABLE systuning_export." + (*itor) + " AS SELECT * FROM " + *itor);
217 ExecuteSql(exportSql);
218 }
219 }
220 std::string createArgsView =
221 "create view systuning_export.args_view AS select A.argset, V2.data as keyName, A.id, D.desc, (case when "
222 "A.datatype==1 then V.data else A.value end) as strValue from args as A left join data_type as D on (D.typeId "
223 "= A.datatype) left join data_dict as V on V.id = A.value left join data_dict as V2 on V2.id = A.key";
224 ExecuteSql(createArgsView);
225 std::string updateProcessName =
226 "update process set name = (select name from thread t where t.ipid = process.id and t.name is not null and "
227 "is_main_thread = 1)";
228 ExecuteSql(updateProcessName);
229 std::string detachSql("DETACH DATABASE systuning_export");
230 ExecuteSql(detachSql);
231
232 if (resultCallBack != nullptr) {
233 wasmDBName_ = outputName;
234 SendDatabase(resultCallBack);
235 }
236 return 0;
237 }
238
Prepare()239 void TraceDataDB::Prepare()
240 {
241 if (pared_) {
242 return;
243 }
244 pared_ = true;
245 ExecuteSql(
246 "update thread set ipid = \
247 (select id from process where \
248 thread.tid = process.pid) where thread.ipid is null;");
249 std::string createArgsView =
250 "create view args_view AS select A.argset, V2.data as keyName, A.id, D.desc, (case when "
251 "A.datatype==1 then V.data else A.value end) as strValue from args as A left join data_type as D on "
252 "(D.typeId "
253 "= A.datatype) left join data_dict as V on V.id = A.value left join data_dict as V2 on V2.id = A.key";
254 ExecuteSql(createArgsView);
255
256 std::string updateProcessNewName =
257 "update process set name = (select name from thread t where t.ipid = process.id and t.name is not "
258 "null and "
259 "is_main_thread = 1)";
260 ExecuteSql(updateProcessNewName);
261 }
ExecuteSql(const std::string_view & sql)262 void TraceDataDB::ExecuteSql(const std::string_view& sql)
263 {
264 sqlite3_stmt* stmt = nullptr;
265 int32_t ret = sqlite3_prepare_v2(db_, sql.data(), static_cast<int32_t>(sql.size()), &stmt, nullptr);
266
267 while (!ret) {
268 int32_t err = sqlite3_step(stmt);
269 if (err == SQLITE_ROW) {
270 continue;
271 }
272 if (err == SQLITE_DONE) {
273 break;
274 }
275 ret = err;
276 }
277
278 sqlite3_finalize(stmt);
279 }
SearchData()280 std::vector<std::string> TraceDataDB::SearchData()
281 {
282 std::vector<std::string> values = {};
283 Prepare();
284 std::string line;
285 bool printResult = false;
286 for (;;) {
287 std::cout << "> ";
288 getline(std::cin, line);
289 if (line.empty()) {
290 std::cout << "If you want to quit either type -q or press CTRL-Z" << std::endl;
291 continue;
292 }
293 values.clear();
294 std::string option = "";
295 ParseCommandLine(option, line, values);
296 if (!line.compare("-q") || !line.compare("-quit")) {
297 break;
298 } else if (!line.compare("-e")) {
299 TS_LOGI("the db file will be at current folder, the name is default.db");
300 (void)ExportDatabase("default.db");
301 return values;
302 } else if (!line.compare("-help") || !line.compare("-h")) {
303 std::cout << "use info" << std::endl;
304 continue;
305 } else if (!line.compare("-p")) {
306 std::cout << "will print result of query" << std::endl;
307 printResult = true;
308 continue;
309 } else if (!option.compare("-s")) {
310 if (!values.empty()) {
311 return values;
312 }
313 continue;
314 } else if (!line.compare("-up")) {
315 std::cout << "will not print result of query" << std::endl;
316 printResult = false;
317 continue;
318 } else if (line.find("-c:") != std::string::npos) {
319 line = line.substr(strlen("-c:"));
320 if (OperateDatabase(line) == SQLITE_OK) {
321 printf("operate SQL success\n");
322 }
323 continue;
324 }
325 PrintSearchResult(line, printResult);
326 }
327 return values;
328 }
ParseCommandLine(std::string & option,std::string line,std::vector<std::string> & values)329 void TraceDataDB::ParseCommandLine(std::string& option, std::string line, std::vector<std::string>& values)
330 {
331 size_t pos = std::string::npos;
332 if ((pos = line.find(" ")) != std::string::npos) {
333 option = line.substr(0, pos);
334 auto left = line.substr(pos + 1);
335 while ((pos = left.find(",")) != std::string::npos) {
336 values.push_back(left.substr(0, pos + 1));
337 left = left.substr(pos + 1);
338 }
339 values.push_back(left);
340 }
341 printf("option:%s\n", option.c_str());
342 }
PrintSearchResult(std::string line,bool printResult)343 void TraceDataDB::PrintSearchResult(std::string line, bool printResult)
344 {
345 using namespace std::chrono;
346 const auto start = steady_clock::now();
347 int32_t rowCount = SearchDatabase(line, printResult);
348 std::chrono::nanoseconds searchDur = duration_cast<nanoseconds>(steady_clock::now() - start);
349 printf("\"%s\"\n\tused %.3fms row: %d\n", line.c_str(), searchDur.count() / 1E6, rowCount);
350 }
SearchDatabase(std::string & sql,bool print)351 int32_t TraceDataDB::SearchDatabase(std::string& sql, bool print)
352 {
353 Prepare();
354 int32_t rowCount = 0;
355 sqlite3_stmt* stmt = nullptr;
356 int32_t ret = sqlite3_prepare_v2(db_, sql.c_str(), static_cast<int32_t>(sql.size()), &stmt, nullptr);
357 if (sql.back() != '\n') {
358 sql += "\r\n";
359 }
360 printf("Executing sql: %s", sql.c_str());
361 if (ret != SQLITE_OK) {
362 TS_LOGE("sqlite3_prepare_v2(%s) failed: %d:%s", sql.c_str(), ret, sqlite3_errmsg(db_));
363 return 0;
364 }
365
366 int32_t colCount = sqlite3_column_count(stmt);
367 if (print) {
368 for (int32_t i = 0; i < colCount; i++) {
369 printf("%s\t", sqlite3_column_name(stmt, i));
370 }
371 printf("\n");
372 }
373
374 while (sqlite3_step(stmt) == SQLITE_ROW) {
375 rowCount++;
376 for (int32_t i = 0; i < colCount; i++) {
377 const char* p = reinterpret_cast<const char*>(sqlite3_column_text(stmt, i));
378 int32_t type = sqlite3_column_type(stmt, i);
379 if (!print) {
380 continue;
381 }
382 if (p == nullptr) {
383 printf("null\t");
384 continue;
385 }
386 if (type == SQLITE_TEXT) {
387 printf("\"%s\"\t", p);
388 } else {
389 printf("%s\t", p);
390 }
391 }
392 if (print) {
393 printf("\n");
394 }
395 }
396 sqlite3_finalize(stmt);
397 return rowCount;
398 }
OperateDatabase(const std::string & sql)399 int32_t TraceDataDB::OperateDatabase(const std::string& sql)
400 {
401 Prepare();
402 char* errmsg = nullptr;
403 int32_t ret = sqlite3_exec(db_, sql.c_str(), NULL, NULL, &errmsg);
404 if (ret != SQLITE_OK && errmsg) {
405 TS_LOGE("sqlite3_exec(%s) failed: %d:%s", sql.c_str(), ret, errmsg);
406 sqlite3_free(errmsg);
407 }
408 return ret;
409 }
410
SearchDatabaseToProto(const std::string & data,SqllitePreparCacheData::TLVResultCallBack resultCallBack)411 int32_t TraceDataDB::SearchDatabaseToProto(const std::string& data,
412 SqllitePreparCacheData::TLVResultCallBack resultCallBack)
413 {
414 TS_CHECK_TRUE(data.size() > SqllitePreparCacheData::TYPE_SIZE && resultCallBack != nullptr, 1,
415 "data.size(%zu) <= sizeof(uint32_t) or resultCallBack is nullptr", data.size());
416 uint32_t type = INVALID_UINT32;
417 auto sqlItor = data.begin() + SqllitePreparCacheData::TYPE_SIZE;
418 std::copy(data.begin(), sqlItor, reinterpret_cast<uint8_t*>(&type));
419 std::string sql(sqlItor, data.end());
420 TS_LOGI("type(%u), sql(%s)", type, sql.data());
421 Prepare();
422 sqlite3_stmt* stmt = nullptr;
423 std::unique_ptr<sqlite3_stmt, void (*)(sqlite3_stmt*)> stmtScope(stmt, SqliteFinalize);
424 int32_t ret = sqlite3_prepare_v2(db_, sql.c_str(), static_cast<int32_t>(sql.size()), &stmt, nullptr);
425 TS_CHECK_TRUE(ret == SQLITE_OK, ret, "sqlite3_prepare_v2(%s) failed: %d:%s", sql.c_str(), ret, sqlite3_errmsg(db_));
426 auto queryFuncItor = sqlPreparCacheData_.sphQueryFuncMap_.find(type);
427 if (queryFuncItor != sqlPreparCacheData_.sphQueryFuncMap_.end()) {
428 queryFuncItor->second(stmt, type, resultCallBack);
429 } else {
430 TS_LOGE("Can't find sph query type:%u", type);
431 return 1;
432 }
433 return ret;
434 }
435
SearchDatabase(const std::string & sql)436 std::string TraceDataDB::SearchDatabase(const std::string& sql)
437 {
438 Prepare();
439 sqlite3_stmt* stmt = nullptr;
440 int32_t ret = sqlite3_prepare_v2(db_, sql.c_str(), static_cast<int32_t>(sql.size()), &stmt, nullptr);
441 if (ret != SQLITE_OK) {
442 TS_LOGE("sqlite3_prepare_v2(%s) failed: %d:%s", sql.c_str(), ret, sqlite3_errmsg(db_));
443 return "";
444 }
445
446 std::string res = "ok\r\n";
447 int32_t colCount = sqlite3_column_count(stmt);
448 if (colCount == 0) {
449 return "";
450 }
451 res += "{\"columns\":[";
452 for (int32_t i = 0; i < colCount; i++) {
453 res += "\"";
454 res += sqlite3_column_name(stmt, i);
455 res += "\",";
456 }
457 res.pop_back();
458 res += "],\"values\":[";
459 bool hasRow = false;
460 std::string row;
461 row.reserve(DEFAULT_LEN_ROW_STRING);
462 while (sqlite3_step(stmt) == SQLITE_ROW) {
463 hasRow = true;
464 GetRowString(stmt, colCount, row);
465 res += row + ",";
466 }
467 if (hasRow) {
468 res.pop_back();
469 }
470 res += "]}\r\n";
471
472 sqlite3_finalize(stmt);
473 return res;
474 }
475
SearchDatabase(const std::string & sql,ResultCallBack resultCallBack)476 int32_t TraceDataDB::SearchDatabase(const std::string& sql, ResultCallBack resultCallBack)
477 {
478 Prepare();
479 sqlite3_stmt* stmt = nullptr;
480 int32_t ret = sqlite3_prepare_v2(db_, sql.c_str(), static_cast<int32_t>(sql.size()), &stmt, nullptr);
481 if (ret != SQLITE_OK) {
482 resultCallBack("false\r\n", SEND_FINISH);
483 TS_LOGE("sqlite3_prepare_v2(%s) failed: %d:%s", sql.c_str(), ret, sqlite3_errmsg(db_));
484 return ret;
485 }
486 if (!resultCallBack) {
487 return ret;
488 }
489
490 std::string res = "ok\r\n";
491 int32_t colCount = sqlite3_column_count(stmt);
492 if (colCount == 0) {
493 resultCallBack(res, SEND_FINISH);
494 return ret;
495 }
496 res += "{\"columns\":[";
497 for (int32_t i = 0; i < colCount; i++) {
498 res += "\"";
499 res += sqlite3_column_name(stmt, i);
500 res += "\",";
501 }
502 res.pop_back(); // remove the last ","
503 res += "],\"values\":[";
504 bool hasRow = false;
505 std::string row;
506 row.reserve(DEFAULT_LEN_ROW_STRING);
507 while (sqlite3_step(stmt) == SQLITE_ROW) {
508 hasRow = true;
509 GetRowString(stmt, colCount, row);
510 res += row + ",";
511 if (res.size() >= ONCE_MAX_MB) {
512 resultCallBack(res, SEND_CONTINUE);
513 res = "";
514 }
515 }
516 if (hasRow) {
517 res.pop_back(); // remove the last ','
518 }
519 res += "]}\r\n";
520 resultCallBack(res, SEND_FINISH);
521
522 sqlite3_finalize(stmt);
523 return ret;
524 }
SearchDatabase(const std::string & sql,uint8_t * out,int32_t outLen)525 int32_t TraceDataDB::SearchDatabase(const std::string& sql, uint8_t* out, int32_t outLen)
526 {
527 Prepare();
528 sqlite3_stmt* stmt = nullptr;
529 std::unique_ptr<sqlite3_stmt, void (*)(sqlite3_stmt*)> stmtLocal(stmt, SqliteFinalize);
530 int32_t ret = sqlite3_prepare_v2(db_, sql.c_str(), static_cast<int32_t>(sql.size()), &stmt, nullptr);
531 if (ret != SQLITE_OK) {
532 TS_LOGE("sqlite3_prepare_v2(%s) failed: %d:%s", sql.c_str(), ret, sqlite3_errmsg(db_));
533 return -1;
534 }
535 stmtLocal.reset(stmt);
536 std::string snprintfInfo("ok");
537 char* res = reinterpret_cast<char*>(out);
538 int32_t retSnprintf = snprintf_s(res, outLen, snprintfInfo.size(), snprintfInfo.data());
539 if (retSnprintf < 0) {
540 return -1;
541 }
542 int32_t pos = retSnprintf;
543 int32_t colCount = sqlite3_column_count(stmt);
544 if (colCount == 0) {
545 return pos;
546 }
547 auto returnvalue = HandleColumnNames(stmt, res, outLen, pos, colCount);
548 if (returnvalue == -1) {
549 return -1;
550 }
551 pos = returnvalue;
552 return HandleRowData(stmt, res, outLen, pos, colCount);
553 }
HandleColumnNames(sqlite3_stmt * stmt,char * res,int32_t outLen,int32_t pos,int32_t colCount)554 int32_t TraceDataDB::HandleColumnNames(sqlite3_stmt* stmt, char* res, int32_t outLen, int32_t pos, int32_t colCount)
555 {
556 std::string snprintfInfo = "{\"columns\":[";
557 int32_t retSnprintf = snprintf_s(res + pos, outLen - pos, snprintfInfo.size(), "%s", snprintfInfo.c_str());
558 if (retSnprintf < 0) {
559 return -1;
560 }
561 pos += retSnprintf;
562 for (int32_t i = 0; i < colCount; i++) {
563 snprintfInfo = "\"" + std::string(sqlite3_column_name(stmt, i)) + "\",";
564 retSnprintf = snprintf_s(res + pos, outLen - pos, snprintfInfo.size(), "%s", snprintfInfo.c_str());
565 if (retSnprintf < 0) {
566 return -1;
567 }
568 pos += retSnprintf;
569 }
570 pos--; // Remove the last ','
571 snprintfInfo = "],\"values\":[";
572 retSnprintf = snprintf_s(res + pos, outLen - pos, snprintfInfo.size(), snprintfInfo.data());
573 if (retSnprintf < 0) {
574 return -1;
575 }
576 pos += retSnprintf;
577 return pos;
578 }
HandleRowData(sqlite3_stmt * stmt,char * res,int32_t outLen,int32_t pos,int32_t colCount)579 int32_t TraceDataDB::HandleRowData(sqlite3_stmt* stmt, char* res, int32_t outLen, int32_t pos, int32_t colCount)
580 {
581 std::string snprintfInfo;
582 int32_t retSnprintf;
583 bool hasRow = false;
584 std::string row;
585 row.reserve(DEFAULT_LEN_ROW_STRING);
586 while (sqlite3_step(stmt) == SQLITE_ROW) {
587 hasRow = true;
588 GetRowString(stmt, colCount, row);
589 if (pos + row.size() + strlen(",]}\r\n") >= size_t(outLen)) {
590 retSnprintf = snprintf_s(res + pos, outLen - pos, 1, "]}\r\n");
591 if (retSnprintf < 0) {
592 return -1;
593 }
594 pos += retSnprintf;
595 sqlite3_finalize(stmt);
596 return pos;
597 }
598 snprintfInfo = row + ",";
599 retSnprintf = snprintf_s(res + pos, outLen - pos, snprintfInfo.size(), "%s", snprintfInfo.c_str());
600 if (retSnprintf < 0) {
601 return -1;
602 }
603 pos += retSnprintf;
604 }
605 if (hasRow) {
606 pos--; // remove the last ','
607 }
608 snprintfInfo = "]}\r\n";
609 retSnprintf = snprintf_s(res + pos, outLen - pos, snprintfInfo.size(), snprintfInfo.c_str());
610 if (retSnprintf < 0) {
611 return -1;
612 }
613 pos += retSnprintf;
614 return pos;
615 }
SetCancel(bool cancel)616 void TraceDataDB::SetCancel(bool cancel)
617 {
618 cancelQuery_ = cancel;
619 }
GetRowString(sqlite3_stmt * stmt,int32_t colCount,std::string & rowStr)620 void TraceDataDB::GetRowString(sqlite3_stmt* stmt, int32_t colCount, std::string& rowStr)
621 {
622 rowStr.clear();
623 rowStr = "[";
624 for (int32_t i = 0; i < colCount; i++) {
625 const char* p = reinterpret_cast<const char*>(sqlite3_column_text(stmt, i));
626 if (p == nullptr) {
627 rowStr += "null,";
628 continue;
629 }
630 int32_t type = sqlite3_column_type(stmt, i);
631 switch (type) {
632 case SQLITE_TEXT:
633 rowStr += FormatString(p);
634 break;
635 default:
636 rowStr += p;
637 break;
638 }
639 rowStr += ",";
640 }
641 rowStr.pop_back(); // remove the last ','
642 rowStr += "]";
643 }
SqliteFinalize(sqlite3_stmt * ptr)644 void TraceDataDB::SqliteFinalize(sqlite3_stmt* ptr)
645 {
646 if (ptr != nullptr) {
647 sqlite3_finalize(ptr);
648 ptr = nullptr;
649 }
650 }
651 } // namespace TraceStreamer
652 } // namespace SysTuning
653