~aleteoryx/muditaos

ref: 57c7672f8f4324526dd63c614b6089fa1a9fc021 muditaos/module-db/Database/Database.cpp -rw-r--r-- 5.6 KiB
57c7672f — Piotr Tanski [EGD-4366] Global data cleanup. (#999) 5 years ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "Database.hpp"
#include "log/log.hpp"
#include "vfs.hpp"
#include <assert.h>
#include <memory>

/* Declarations *********************/
extern sqlite3_vfs *sqlite3_ecophonevfs(void);

extern "C"
{

    int sqlite3_os_init(void)
    {
        /*
         ** The following macro defines an initializer for an sqlite3_vfs object.
         ** The name of the VFS is NAME.  The pAppData is a pointer to a pointer
         ** to the "finder" function.  (pAppData is a pointer to a pointer because
         ** silly C90 rules prohibit a void* from being cast to a function pointer
         ** and so we have to go through the intermediate pointer to avoid problems
         ** when compiling with -pedantic-errors on GCC.)
         **
         ** The FINDER parameter to this macro is the name of the pointer to the
         ** finder-function.  The finder-function returns a pointer to the
         ** sqlite_io_methods object that implements the desired locking
         ** behaviors.  See the division above that contains the IOMETHODS
         ** macro for addition information on finder-functions.
         **
         ** Most finders simply return a pointer to a fixed sqlite3_io_methods
         ** object.  But the "autolockIoFinder" available on MacOSX does a little
         ** more than that; it looks at the filesystem type that hosts the
         ** database file and tries to choose an locking method appropriate for
         ** that filesystem time.
         */

        sqlite3_vfs_register(sqlite3_ecophonevfs(), 1);

        return SQLITE_OK;
    }

    /*
     ** Shutdown the operating system interface.
     **
     ** Some operating systems might need to do some cleanup in this routine,
     ** to release dynamically allocated objects.  But not on unix.
     ** This routine is a no-op for unix.
     */
    int sqlite3_os_end(void)
    {

        return SQLITE_OK;
    }

    /* Internal Defines ***********************/
    void errorLogCallback(void *pArg, int iErrCode, const char *zMsg)
    {
        LOG_ERROR("(%d) %s\n", iErrCode, zMsg);
    }
}

Database::Database(const char *name) : dbConnection(nullptr), dbName(name), isInitialized_(false)
{
    LOG_INFO("creating database: %s", dbName.c_str());
    auto rc = sqlite3_open(name, &dbConnection);
    if (rc != SQLITE_OK) {
        LOG_ERROR("SQLITE INITIALIZATION ERROR! rc=%d dbName=%s", rc, name);
    }
    assert(rc == SQLITE_OK);
    pragmaQuery("PRAGMA integrity_check;");
    pragmaQuery("PRAGMA locking_mode=EXCLUSIVE");
}

Database::~Database()
{
    sqlite3_close(dbConnection);
}

void Database::initialize()
{
    sqlite3_config(
        SQLITE_CONFIG_LOG,
        errorLogCallback,
        (void *)1); //(void*)1 is taken from official SQLITE examples and it appears that it ends variable args list
    sqlite3_initialize();
}
void Database::deinitialize()
{
    sqlite3_shutdown();
}

bool Database::execute(const char *format, ...)
{
    if (!format) {
        return false;
    }

    va_list ap;
    char *szQuery = static_cast<char *>(sqlite3_malloc(maxQueryLen));
    va_start(ap, format);
    sqlite3_vsnprintf(maxQueryLen, (char *)szQuery, format, ap);
    va_end(ap);

    int result = sqlite3_exec(dbConnection, szQuery, NULL, NULL, NULL);
    if (result != SQLITE_OK)
        LOG_ERROR("Execution of \'%s\' failed with %d", szQuery, result);

    sqlite3_free(szQuery);

    return result != SQLITE_OK ? false : true;
}

std::unique_ptr<QueryResult> Database::query(const char *format, ...)
{

    if (!format) {
        return nullptr;
    }

    va_list ap;
    char *szQuery = static_cast<char *>(sqlite3_malloc(maxQueryLen));
    va_start(ap, format);
    szQuery[0] = 0;
    sqlite3_vsnprintf(maxQueryLen, szQuery, format, ap);
    va_end(ap);

    auto queryResult = std::make_unique<QueryResult>();

    int result = sqlite3_exec(dbConnection, szQuery, queryCallback, queryResult.get(), NULL);
    if (result != SQLITE_OK) {
        LOG_ERROR("SQL query \'%s\' failed selecting : %d", szQuery, result);
        return nullptr;
    }

    sqlite3_free(szQuery);

    return queryResult;
}

int Database::queryCallback(void *usrPtr, int count, char **data, char **columns)
{
    QueryResult *db = reinterpret_cast<QueryResult *>(usrPtr);

    std::vector<Field> row;
    for (uint32_t i = 0; i < (uint32_t)count; i++) {
        try {
            row.push_back(Field{data[i]});
        }
        catch (...) {
            LOG_FATAL("Error on: %" PRIu32 " %s", i, data[i]);
        }
    }

    db->addRow(row);

    return 0;
}

uint32_t Database::getLastInsertRowId()
{
    return sqlite3_last_insert_rowid(dbConnection);
}

void Database::pragmaQuery(const std::string &pragmaStatemnt)
{
    auto results = query(pragmaStatemnt.c_str());
    if (results) {
        uint32_t fieldsCount = results->getFieldCount();
        do {
            for (uint32_t i = 0; i < fieldsCount; i++) {
                Field field = (*results)[i];
                LOG_INFO("%s: '%s'", pragmaStatemnt.c_str(), field.getCString());
            }
        } while (results->nextRow());
    }
    else {
        LOG_DEBUG("no results!");
    }
}

bool Database::storeIntoFile(const std::string &backupPath)
{
    LOG_INFO("Backup database: %s, into file: %s - STARTED", dbName.c_str(), backupPath.c_str());

    auto rc = execute("VACUUM INTO '%q';", backupPath.c_str());

    if (rc == true) {
        LOG_INFO("Backup database: %s, into file: %s - SUCCEDED", dbName.c_str(), backupPath.c_str());
    }
    else {
        LOG_ERROR("Backup database: %s, into file: %s - FAILED", dbName.c_str(), backupPath.c_str());
    }

    return rc;
}