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