/* * Copyright (c) 2023 Fancy Code. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "SqliteHandle.h" #include "IFilesManager.h" #include "ILog.h" #include "sqlite3.h" #include #include #include #include #include #include #include #include #define FILES_TABLE "files" #define TABLE_KEY "key" #define FILE_PATH "path" #define CREATE_TIME "create_time" #define FILE_TYPE "type" #define FILE_SIZE "size" #define FILE_STATUS "status" #define FILE_DURATION "duration" #define FILE_STATUS_BE_RECORDING "recording" #define FILE_STATUS_COMPLETE_RECORD "complete_record" #define FILE_STATUS_SHOULD_BE_UPLOADED "should_be_uploaded" #define FILE_STATUS_UPLOADING "uploading" #define FILE_STATUS_UPLOADED "uploaded" #define FIEL_TYPE_PIR "pir" #define FIEL_TYPE_MANUAL_TEST "manual_test" #define FIEL_TYPE_MANUAL_PHONE "manual_phone" #define FIEL_TYPE_TIMED "timed" #define FILE_TYPE_UNDEFINE "undefine" SqliteHandle::SqliteHandle() : mDb(nullptr) { } std::shared_ptr &SqliteHandle::GetInstance(std::shared_ptr *impl) { static auto instance = std::make_shared(); if (impl) { if (instance.use_count() == 1) { LogInfo("Instance changed succeed.\n"); instance = *impl; } else { LogError("Can't changing the instance becase of using by some one.\n"); } } return instance; } void SqliteHandle::Init(const std::string &dbFileName) { if (nullptr != mDb) { LogWarning("SqliteHandle has been init.\n"); return; } int rc = SQLITE_UNDEFINE; rc = sqlite3_open(dbFileName.c_str(), &mDb); if (SQLITE_OK != rc) { LogError("open sqlite3 failed: %s\n", sqlite3_errmsg(mDb)); sqlite3_close(mDb); return; } DbInit(mDb); } void SqliteHandle::UnInit(void) { if (mDb) { sqlite3_close(mDb); mDb = nullptr; } } unsigned long int SqliteHandle::CreateFiles(const unsigned int &count) { char *err_msg = nullptr; int rc = SQLITE_UNDEFINE; const char *sql = "INSERT INTO " FILES_TABLE " (" FILE_PATH ", " CREATE_TIME ", " FILE_TYPE ", " FILE_SIZE ", " FILE_STATUS ", " FILE_DURATION ") VALUES (\"\", 0, \"" FILE_TYPE_UNDEFINE "\", 0, \"" FILE_STATUS_BE_RECORDING "\", 0);"; for (unsigned int i = 0; i < count; ++i) { rc = sqlite3_exec(mDb, sql, nullptr, nullptr, &err_msg); if (SQLITE_OK != rc) { LogError("SQL error: %s\n", err_msg); sqlite3_free(err_msg); return 0; } } auto last_rowid_lambda = [](void *last_rowid, int argc, char **argv, char **azColName) -> int { if (argc > 0) { LogInfo("last_rowid key = %s\n", argv[0]); *(unsigned long int *)last_rowid = strtoul(argv[0], nullptr, 10); } return 0; }; unsigned long int last_rowid = 0; const char *sql2 = "SELECT last_insert_rowid();"; rc = sqlite3_exec(mDb, sql2, last_rowid_lambda, &last_rowid, &err_msg); if (SQLITE_OK != rc) { LogError("SQL error: %s\n", err_msg); sqlite3_free(err_msg); return 0; } constexpr int MINIMUM_AUTO_INCREMENT_PRIMARY_KEY = 1; return last_rowid - count + MINIMUM_AUTO_INCREMENT_PRIMARY_KEY; } bool SqliteHandle::SyncFile(const SyncFileInfo &info) { if (UNDEFINE_SERIAL_NUMBER == info.mSerialNumber) { LogError("Serial number is undefine.\n"); return false; } std::stringstream sqlStream; std::string comma = " "; sqlStream << "UPDATE " FILES_TABLE " SET "; if (UNDEFINE_CREATE_TIME != info.mCreateTime_s) { sqlStream << comma << CREATE_TIME " = '" << info.mCreateTime_s << "'"; comma = ", "; } if (info.mFileName.empty() == false) { sqlStream << comma << FILE_PATH " = '" << info.mFileName << "'"; comma = ", "; } if (UNDEFINE_FILE_SIZE != info.mFileSize) { sqlStream << comma << FILE_SIZE " = '" << info.mFileSize << "'"; comma = ", "; } if (FileStatus::END != info.mStatus) { sqlStream << comma << FILE_STATUS " = '" << ConvertFileStatusToString(info.mStatus) << "'"; comma = ", "; } if (FileCreateType::END != info.mType) { sqlStream << comma << FILE_TYPE " = '" << ConvertFileTypeToString(info.mType) << "'"; comma = ", "; } if (UNDEFINE_FILE_DURATION != info.mFileDuration) { sqlStream << comma << FILE_DURATION " = '" << info.mFileDuration << "'"; comma = ", "; } sqlStream << " WHERE " TABLE_KEY " = " << info.mSerialNumber << ";"; LogInfo("Sql: %s\n", sqlStream.str().c_str()); char *errMsg = nullptr; int rc = SQLITE_UNDEFINE; rc = sqlite3_exec(mDb, sqlStream.str().c_str(), nullptr, nullptr, &errMsg); if (SQLITE_OK != rc) { LogError("SQL error: %s\n", errMsg); sqlite3_free(errMsg); return false; } LogInfo("Sync file success.\n"); return true; } bool SqliteHandle::SearchFiles(const std::vector &types, std::vector &info) { std::string sqlAnd = " "; // if (types.size() > 1) { // sqlAnd = " AND "; // } constexpr FileCreateType END_MEANS_SEARCHING_ALL_FILES = FileCreateType::END; std::stringstream sqlStream; if (types.size() == 1 && types[0] == END_MEANS_SEARCHING_ALL_FILES) { sqlStream << "SELECT * from " FILES_TABLE << ";"; } else { sqlStream << "SELECT * from " FILES_TABLE " WHERE "; for (auto &type : types) { sqlStream << sqlAnd << FILE_TYPE " = '" << ConvertFileTypeToString(type) << "'"; sqlAnd = " OR "; } sqlStream << ";"; } LogInfo("Sql: %s\n", sqlStream.str().c_str()); return SearchFiles(mDb, sqlStream.str(), info); } void SqliteHandle::DbInit(sqlite3 *db) { if (nullptr == db) { LogError("db is null.\n"); return; } char *errMsg = nullptr; int rc = SQLITE_UNDEFINE; const char *sql = "CREATE TABLE IF NOT EXISTS " FILES_TABLE " (" TABLE_KEY " INTEGER PRIMARY KEY AUTOINCREMENT, " FILE_PATH " TEXT, " CREATE_TIME " INTEGER," FILE_TYPE " TEXT, " FILE_SIZE " INTEGER, " FILE_STATUS " TEXT," FILE_DURATION " INTEGER);"; rc = sqlite3_exec(db, sql, nullptr, nullptr, &errMsg); if (SQLITE_OK != rc) { LogError("Sql: %s, errMsg: %s\n", sql, errMsg); sqlite3_free(errMsg); } else { LogInfo("Sqlite init success. table = %s\n", FILES_TABLE); } } bool SqliteHandle::UpdateCreateTime(sqlite3 *db, const unsigned long &key, const time_t &createTime) { if (nullptr == db) { LogError("db is null.\n"); return false; } char *errMsg = nullptr; int rc = SQLITE_UNDEFINE; if (UNDEFINE_CREATE_TIME != createTime) { std::stringstream sqlStream; sqlStream << "UPDATE " FILES_TABLE " SET " CREATE_TIME " = '" << createTime << "' WHERE " TABLE_KEY " = " << key << ";"; LogInfo("Sql: %s\n", sqlStream.str().c_str()); rc = sqlite3_exec(db, sqlStream.str().c_str(), nullptr, nullptr, &errMsg); if (SQLITE_OK != rc) { LogError("SQL error: %s\n", errMsg); sqlite3_free(errMsg); return false; } } return true; } bool SqliteHandle::UpdateFileName(sqlite3 *db, const unsigned long &key, const std::string &fileName) { if (nullptr == db) { LogError("db is null.\n"); return false; } char *errMsg = nullptr; int rc = SQLITE_UNDEFINE; if (fileName.empty() == false) { std::stringstream sqlStream; sqlStream << "UPDATE " FILES_TABLE " SET " FILE_PATH " = '" << fileName << "' WHERE " TABLE_KEY " = " << key << ";"; LogInfo("Sql: %s\n", sqlStream.str().c_str()); rc = sqlite3_exec(db, sqlStream.str().c_str(), nullptr, nullptr, &errMsg); if (SQLITE_OK != rc) { LogError("SQL error: %s\n", errMsg); sqlite3_free(errMsg); return false; } } return true; } bool SqliteHandle::UpdateFileSize(sqlite3 *db, const unsigned long &key, const unsigned long &fileSize) { if (nullptr == db) { LogError("db is null.\n"); return false; } char *errMsg = nullptr; int rc = SQLITE_UNDEFINE; if (UNDEFINE_FILE_SIZE != fileSize) { std::stringstream sqlStream; sqlStream << "UPDATE " FILES_TABLE " SET " FILE_SIZE " = '" << fileSize << "' WHERE " TABLE_KEY " = " << key << ";"; LogInfo("Sql: %s\n", sqlStream.str().c_str()); rc = sqlite3_exec(db, sqlStream.str().c_str(), nullptr, nullptr, &errMsg); if (SQLITE_OK != rc) { LogError("SQL error: %s\n", errMsg); sqlite3_free(errMsg); return false; } } return true; } bool SqliteHandle::UpdateFileType(sqlite3 *db, const unsigned long &key, const FileCreateType &type) { if (nullptr == db) { LogError("db is null.\n"); return false; } char *errMsg = nullptr; int rc = SQLITE_UNDEFINE; if (FileCreateType::END != type) { std::stringstream sqlStream; sqlStream << "UPDATE " FILES_TABLE " SET " FILE_TYPE " = '" << ConvertFileTypeToString(type) << "' WHERE " TABLE_KEY " = " << key << ";"; LogInfo("Sql: %s\n", sqlStream.str().c_str()); rc = sqlite3_exec(db, sqlStream.str().c_str(), nullptr, nullptr, &errMsg); if (SQLITE_OK != rc) { LogError("SQL error: %s\n", errMsg); sqlite3_free(errMsg); return false; } } return true; } bool SqliteHandle::UpdateFileDuration(sqlite3 *db, const unsigned long &key, const unsigned int &duration) { if (nullptr == db) { LogError("db is null.\n"); return false; } char *errMsg = nullptr; int rc = SQLITE_UNDEFINE; std::stringstream sqlStream; sqlStream << "UPDATE " FILES_TABLE " SET " FILE_DURATION " = '" << duration << "' WHERE " TABLE_KEY " = " << key << ";"; LogInfo("Sql: %s\n", sqlStream.str().c_str()); rc = sqlite3_exec(db, sqlStream.str().c_str(), nullptr, nullptr, &errMsg); if (SQLITE_OK != rc) { LogError("SQL error: %s\n", errMsg); sqlite3_free(errMsg); return false; } return true; } bool SqliteHandle::SearchFiles(sqlite3 *db, const std::string &sql, std::vector &info) { if (nullptr == db) { LogError("db is null.\n"); return false; } auto dbCallback = [](void *data, int argc, char **argv, char **azColName) -> int { /********************** Do not delete this code to avoid debugging. *********************/ int i = 0; fprintf(stderr, "%s: ", "searchFiles"); for (i = 0; i < argc; i++) { printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL"); } printf("\n"); /********************** Do not delete this code to avoid debugging. *********************/ /** * @brief The magic number in the argv variable refers to the SQL statement that creates the form, which is as * follows: * CREATE TABLE IF NOT EXISTS files (key INTEGER PRIMARY KEY AUTOINCREMENT, path TEXT, create_time INTEGER,type * 0 1 2 3 * TEXT, size INTEGER, status TEXT, duration INTEGER); * 4 5 6 */ constexpr int TABLE_MEMBER_NUM = 7; if (TABLE_MEMBER_NUM != argc) { LogError("Something wrong happened, argc = %d.\n", argc); return 0; } std::vector *info = (std::vector *)data; const unsigned long serialNumber = std::stoul(argv[0]); const std::string fileName = argv[1]; const unsigned int fileSize = std::stoi(argv[4]); const unsigned int fileDuration = std::stoi(argv[6]); const time_t createTime_s = std::stol(argv[2]); const std::string typeString(argv[3]); const FileCreateType type = SqliteHandle::ConvertStringToFileType(typeString); const std::string statusString(argv[5]); const FileStatus status = SqliteHandle::ConvertStringToFileStatus(statusString); SyncFileInfo fileInfo(serialNumber, fileName, fileSize, fileDuration, createTime_s, type, status); (*info).push_back(fileInfo); return 0; }; char *errMsg = nullptr; int rc = SQLITE_UNDEFINE; rc = sqlite3_exec(db, sql.c_str(), dbCallback, &info, &errMsg); if (SQLITE_OK != rc) { LogError("SQL error: %s\n", errMsg); sqlite3_free(errMsg); return false; } return true; } std::string SqliteHandle::ConvertFileTypeToString(const FileCreateType &type) { switch (type) { case FileCreateType::PIR: return FIEL_TYPE_PIR; case FileCreateType::MANUAL_TEST: return FIEL_TYPE_MANUAL_TEST; case FileCreateType::MANUAL_PHONE: return FIEL_TYPE_MANUAL_PHONE; case FileCreateType::TIMED: return FIEL_TYPE_TIMED; case FileCreateType::END: default: return FILE_TYPE_UNDEFINE; } } FileCreateType SqliteHandle::ConvertStringToFileType(const std::string &type) { std::map fileTypeMap; fileTypeMap[FIEL_TYPE_PIR] = FileCreateType::PIR; fileTypeMap[FIEL_TYPE_MANUAL_TEST] = FileCreateType::MANUAL_TEST; fileTypeMap[FIEL_TYPE_MANUAL_PHONE] = FileCreateType::MANUAL_PHONE; fileTypeMap[FIEL_TYPE_TIMED] = FileCreateType::TIMED; fileTypeMap[FILE_TYPE_UNDEFINE] = FileCreateType::END; auto it = fileTypeMap.find(type); if (it != fileTypeMap.end()) { return it->second; } return FileCreateType::END; } bool SqliteHandle::UpdateFileStatus(sqlite3 *db, const unsigned long &key, const FileStatus &status) { if (nullptr == db) { LogError("db is null.\n"); return false; } char *errMsg = nullptr; int rc = SQLITE_UNDEFINE; if (FileStatus::END != status) { std::stringstream sqlStream; sqlStream << "UPDATE " FILES_TABLE " SET " FILE_STATUS " = '" << ConvertFileStatusToString(status) << "' WHERE " TABLE_KEY " = " << key << ";"; LogInfo("Sql: %s\n", sqlStream.str().c_str()); rc = sqlite3_exec(db, sqlStream.str().c_str(), nullptr, nullptr, &errMsg); if (SQLITE_OK != rc) { LogError("SQL error: %s\n", errMsg); sqlite3_free(errMsg); return false; } } return true; } std::string SqliteHandle::ConvertFileStatusToString(const FileStatus &status) { switch (status) { case FileStatus::RECORDING: return "RECORDING"; case FileStatus::FINISHED_RECORD: return "FINISHED_RECORD"; case FileStatus::SHOULD_BE_UPLOAD: return "SHOULD_BE_UPLOAD"; case FileStatus::UPLOADING: return "UPLOADING"; case FileStatus::UPLOADED: return "UPLOADED"; case FileStatus::END: default: return "undefine"; } } FileStatus SqliteHandle::ConvertStringToFileStatus(const std::string &status) { std::map fileStatusMap; fileStatusMap[FILE_STATUS_BE_RECORDING] = FileStatus::RECORDING; fileStatusMap[FILE_STATUS_COMPLETE_RECORD] = FileStatus::FINISHED_RECORD; fileStatusMap[FILE_STATUS_SHOULD_BE_UPLOADED] = FileStatus::SHOULD_BE_UPLOAD; fileStatusMap[FILE_STATUS_UPLOADING] = FileStatus::UPLOADING; fileStatusMap[FILE_STATUS_UPLOADED] = FileStatus::UPLOADED; auto it = fileStatusMap.find(status); if (it != fileStatusMap.end()) { return it->second; } return FileStatus::END; }