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