aboutsummaryrefslogtreecommitdiff
path: root/nix/libstore/sqlite.cc
blob: e08c67f40ed296cb5766ded6af1d55e20e9f6957 (about) (plain)
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
#include "sqlite.hh"
#include "util.hh"

#include <sqlite3.h>

namespace nix {

[[noreturn]] void throwSQLiteError(sqlite3 * db, const format & f)
{
    int err = sqlite3_errcode(db);
    if (err == SQLITE_BUSY || err == SQLITE_PROTOCOL) {
        if (err == SQLITE_PROTOCOL)
            printMsg(lvlError, "warning: SQLite database is busy (SQLITE_PROTOCOL)");
        else {
            static bool warned = false;
            if (!warned) {
                printMsg(lvlError, "warning: SQLite database is busy");
                warned = true;
            }
        }
        /* Sleep for a while since retrying the transaction right away
           is likely to fail again. */
#if HAVE_NANOSLEEP
        struct timespec t;
        t.tv_sec = 0;
        t.tv_nsec = (random() % 100) * 1000 * 1000; /* <= 0.1s */
        nanosleep(&t, 0);
#else
        sleep(1);
#endif
        throw SQLiteBusy(format("%1%: %2%") % f.str() % sqlite3_errmsg(db));
    }
    else
        throw SQLiteError(format("%1%: %2%") % f.str() % sqlite3_errmsg(db));
}

SQLite::~SQLite()
{
    try {
        if (db && sqlite3_close(db) != SQLITE_OK)
            throwSQLiteError(db, "closing database");
    } catch (...) {
        ignoreException();
    }
}

void SQLiteStmt::create(sqlite3 * db, const string & s)
{
    checkInterrupt();
    assert(!stmt);
    if (sqlite3_prepare_v2(db, s.c_str(), -1, &stmt, 0) != SQLITE_OK)
        throwSQLiteError(db, "creating statement");
    this->db = db;
}

SQLiteStmt::~SQLiteStmt()
{
    try {
        if (stmt && sqlite3_finalize(stmt) != SQLITE_OK)
            throwSQLiteError(db, "finalizing statement");
    } catch (...) {
        ignoreException();
    }
}

SQLiteStmt::Use::Use(SQLiteStmt & stmt)
    : stmt(stmt)
{
    assert(stmt.stmt);
    /* Note: sqlite3_reset() returns the error code for the most
       recent call to sqlite3_step().  So ignore it. */
    sqlite3_reset(stmt);
}

SQLiteStmt::Use::~Use()
{
    sqlite3_reset(stmt);
}

SQLiteStmt::Use & SQLiteStmt::Use::operator () (const std::string & value, bool notNull)
{
    if (notNull) {
        if (sqlite3_bind_text(stmt, curArg++, value.c_str(), -1, SQLITE_TRANSIENT) != SQLITE_OK)
            throwSQLiteError(stmt.db, "binding argument");
    } else
        bind();
    return *this;
}

SQLiteStmt::Use & SQLiteStmt::Use::operator () (int64_t value, bool notNull)
{
    if (notNull) {
        if (sqlite3_bind_int64(stmt, curArg++, value) != SQLITE_OK)
            throwSQLiteError(stmt.db, "binding argument");
    } else
        bind();
    return *this;
}

SQLiteStmt::Use & SQLiteStmt::Use::bind()
{
    if (sqlite3_bind_null(stmt, curArg++) != SQLITE_OK)
        throwSQLiteError(stmt.db, "binding argument");
    return *this;
}

int SQLiteStmt::Use::step()
{
    return sqlite3_step(stmt);
}

void SQLiteStmt::Use::exec()
{
    int r = step();
    assert(r != SQLITE_ROW);
    if (r != SQLITE_DONE)
        throwSQLiteError(stmt.db, "executing SQLite statement");
}

bool SQLiteStmt::Use::next()
{
    int r = step();
    if (r != SQLITE_DONE && r != SQLITE_ROW)
        throwSQLiteError(stmt.db, "executing SQLite query");
    return r == SQLITE_ROW;
}

std::string SQLiteStmt::Use::getStr(int col)
{
    auto s = (const char *) sqlite3_column_text(stmt, col);
    assert(s);
    return s;
}

int64_t SQLiteStmt::Use::getInt(int col)
{
    // FIXME: detect nulls?
    return sqlite3_column_int64(stmt, col);
}

SQLiteTxn::SQLiteTxn(sqlite3 * db)
{
    this->db = db;
    if (sqlite3_exec(db, "begin;", 0, 0, 0) != SQLITE_OK)
        throwSQLiteError(db, "starting transaction");
    active = true;
}

void SQLiteTxn::commit()
{
    if (sqlite3_exec(db, "commit;", 0, 0, 0) != SQLITE_OK)
        throwSQLiteError(db, "committing transaction");
    active = false;
}

SQLiteTxn::~SQLiteTxn()
{
    try {
        if (active && sqlite3_exec(db, "rollback;", 0, 0, 0) != SQLITE_OK)
            throwSQLiteError(db, "aborting transaction");
    } catch (...) {
        ignoreException();
    }
}

}
tooltip'>* gnu/home/services/messaging.scm: New file. * gnu/local.mk (GNU_SYSTEM_MODULES): Add it. * po/guix/POTFILES.in: Likewise. * doc/guix.texi (Messaging Home Services): Document it in new subsection. Jan (janneke) Nieuwenhuizen 2023-03-07nls: Fix more Texinfo Italiano....po/guix/it.po: Fix `@esempio`, `@sempio`, `@fine`. Julien Lepiller 2023-03-07nls: Update translations.Julien Lepiller 2023-02-26nls: Fix more Texinfo Italiano....* po/guix/it.po: Fix ‘@opzione’, ‘@comando’. Tobias Geerinckx-Rice 2023-02-26nls: Fix typo in Italian translation....I will, of course, fix this in Weblate or find someone who can, but this currently breaks ‘guix system search cups’. * po/guix/it.po: Fix ‘@dnf’ typo. Reported by tux_life in #guix: https://issues.guix.gnu.org/61961 Tobias Geerinckx-Rice 2023-01-05nls: Update translations....* po/guix/ka.po: New file. * po/guix/LINGUAS: Add it. * po/packages/uk.po: New file. * po/packages/LINGUAS: Add it. Julien Lepiller 2022-12-04nls: Update translations....po/packages/vi.po: New file. po/packages/LINGUAS: Add it. Julien Lepiller 2022-11-20scripts: Use translations for guix.pot for service descriptions....Previously, service descriptions appeared in both guix.pot and packages.pot, but only translations of packages.pot were used. Now, translations are only done with guix.pot. This is better, because translators are more likely to translate guix.pot, and is also easier, because files in gnu/{home/,}services need to be in po/guix/POTFILES.in anyway and po/guix/Makevars already acts on the 'description' keyword because of lint checkers. * guix/scripts/home.scm (service-type-description-string): Use translations from guix.pot. * guix/scripts/system/search.scm (service-type-description-string) (service-type->recutils): Likewise. * po/packages/POTFILES.in: Move files in gnu/services to ... * po/guix/POTFILES.in: ... here. pelzflorian (Florian Pelz) 2022-11-15installer: Report known-unsupported PCI devices....* gnu/installer/hardware.scm: New file. * gnu/local.mk (INSTALLER_MODULES): Add it. * po/guix/POTFILES.in: Add it. * gnu/installer.scm (installer-steps): Pass #:pci-database to the 'welcome' step procedure. * gnu/installer/newt.scm (welcome-page): Add #:pci-database and pass it to 'run-welcome-page'. * gnu/installer/newt/welcome.scm (check-hardware-support): Add #:pci-database. Enumerate unsupported PCI devices and run an error page when unsupported devices are found. (run-welcome-page): Add #:pci-database and pass it to 'check-hardware-support' and to the recursive call. * gnu/installer/record.scm (<installer>)[welcome-page]: Adjust comment. * doc/guix.texi (Hardware Considerations): Mention it. Ludovic Courtès 2022-11-04nls: Update translations....* po/guix/lt.po: New file. * po/guix/LINGUAS: Add lt. Julien Lepiller 2022-10-06nls: Update translations.Julien Lepiller 2022-10-06services: dhcp-client: Implement and use a configuration record....* gnu/services/networking.scm (dhcp-client-configuration): New record configuration. (dhcp-client-shepherd-service): Implement a shepher service. Provide a deprication message for legacy configurations. (dhcp-client-service-type): Use dhcp-client-shepherd-service. * doc/guix.texi (Networking Setup): Update. * po/guix/POTFILES.in: Add 'gnu/services/networking.scm'. Co-authored-by: Ludovic Courtès <ludo@gnu.org> Alexey Abramov 2022-09-24services: Add samba service....* gnu/services/samba.scm: New file. * gnu/tests/samba.scm: New file. * gnu/local.mk (GNU_SYSTEM_MODULES): Add them. * po/guix/POTFILES.in Add 'gnu/services/samba.scm'. * doc/guix.texi: Document it. Signed-off-by: Lars-Dominik Braun <lars@6xq.net> Simon Streit 2022-09-04nls: Update translations.Julien Lepiller 2022-08-11po: Add 'guix/read-print.scm'....This is a followup to b21d05d232ec0aba5abec20e83cc52c1d5163cc3. * po/guix/POTFILES.in: Add 'guix/read-print.scm'. Ludovic Courtès 2022-08-10nls: Update translations....po/guix/bn.po: New file. po/guix/LINGUAS: Add it. Julien Lepiller