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