sqlite3_accessor.h 12 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.


16
17
#ifndef DATASRC_SQLITE3_ACCESSOR_H
#define DATASRC_SQLITE3_ACCESSOR_H
18
19

#include <datasrc/database.h>
20
#include <datasrc/data_source.h>
21

22
23
#include <exceptions/exceptions.h>

24
#include <boost/enable_shared_from_this.hpp>
25
#include <boost/scoped_ptr.hpp>
26
#include <string>
27

28
29
#include <cc/data.h>

30
namespace isc {
31
32
33
34
namespace dns {
class RRClass;
}

35
36
namespace datasrc {

Jelte Jansen's avatar
Jelte Jansen committed
37
38
39
40
41
/// \brief Low-level database error
///
/// This exception is thrown when the SQLite library complains about something.
/// It might mean corrupt database file, invalid request or that something is
/// rotten in the library.
42
class SQLite3Error : public DataSourceError {
43
public:
44
    SQLite3Error(const char* file, size_t line, const char* what) :
45
        DataSourceError(file, line, what) {}
46
};
47

48
49
50
51
52
53
class IncompatibleDbVersion : public Exception {
public:
    IncompatibleDbVersion(const char* file, size_t line, const char* what) :
        isc::Exception(file, line, what) {}
};

Jelte Jansen's avatar
Jelte Jansen committed
54
55
56
57
/// \brief Too Much Data
///
/// Thrown if a query expecting a certain number of rows back returned too
/// many rows.
58
class TooMuchData : public DataSourceError {
59
60
public:
    TooMuchData(const char* file, size_t line, const char* what) :
61
        DataSourceError(file, line, what) {}
62
63
};

Jelte Jansen's avatar
Jelte Jansen committed
64
65
66
67
/// \brief Too Little Data
///
/// Thrown if a query expecting a certain number of rows back returned too
/// few rows (including none).
68
class TooLittleData : public DataSourceError {
69
70
public:
    TooLittleData(const char* file, size_t line, const char* what) :
71
        DataSourceError(file, line, what) {}
72
73
};

74
75
struct SQLite3Parameters;

Jelte Jansen's avatar
Jelte Jansen committed
76
77
78
79
80
/// \brief Concrete implementation of DatabaseAccessor for SQLite3 databases
///
/// This opens one database file with our schema and serves data from there.
/// According to the design, it doesn't interpret the data in any way, it just
/// provides unified access to the DB.
81
82
class SQLite3Accessor : public DatabaseAccessor,
    public boost::enable_shared_from_this<SQLite3Accessor> {
83
public:
Jelte Jansen's avatar
Jelte Jansen committed
84
85
86
87
88
89
90
91
92
93
94
95
    /// \brief Constructor
    ///
    /// This opens the database and becomes ready to serve data from there.
    ///
    /// \exception SQLite3Error will be thrown if the given database file
    /// doesn't work (it is broken, doesn't exist and can't be created, etc).
    ///
    /// \param filename The database file to be used.
    /// \param rrclass Textual representation of RR class ("IN", "CH", etc),
    ///    specifying which class of data it should serve (while the database
    ///    file can contain multiple classes of data, a single accessor can
    ///    work with only one class).
96
97
    SQLite3Accessor(const std::string& filename, const std::string& rrclass);

Jelte Jansen's avatar
Jelte Jansen committed
98
99
100
    /// \brief Destructor
    ///
    /// Closes the database.
101
    virtual ~SQLite3Accessor();
Jelte Jansen's avatar
Jelte Jansen committed
102

103
104
    /// This implementation internally opens a new sqlite3 database for the
    /// same file name specified in the constructor of the original accessor.
105
106
    virtual boost::shared_ptr<DatabaseAccessor> clone();

Jelte Jansen's avatar
Jelte Jansen committed
107
108
109
110
111
112
113
114
115
116
117
    /// \brief Look up a zone
    ///
    /// This implements the getZone from DatabaseAccessor and looks up a zone
    /// in the data. It looks for a zone with the exact given origin and class
    /// passed to the constructor.
    ///
    /// \exception SQLite3Error if something about the database is broken.
    ///
    /// \param name The (fully qualified) domain name of zone to look up
    /// \return The pair contains if the lookup was successful in the first
    ///    element and the zone id in the second if it was.
118
    virtual std::pair<bool, int> getZone(const std::string& name) const;
Jelte Jansen's avatar
Jelte Jansen committed
119

Jelte Jansen's avatar
Jelte Jansen committed
120
121
    /// \brief Add a zone
    ///
122
123
124
    /// This implements the addZone from DatabaseAccessor and adds a zone
    /// into the zones table. If the zone exists already, it is still added,
    /// so the caller should make sure this does not happen (by making
Jelte Jansen's avatar
Jelte Jansen committed
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
    /// sure the zone does not exist). In the case of duplicate addition,
    /// it is undefined which zone id is returned.
    ///
    /// The class of the newly created zone is the class passed at construction
    /// time of the accessor.
    ///
    /// This method requires a transaction has been started (with
    /// \c beginTransaction) by the caller.
    ///
    /// \exception DataSourceError if no transaction is active, or if there
    ///                           is an SQLite3 error when performing the
    ///                           queries.
    ///
    /// \param name The origin name of the zone to add
    /// \return the id of the zone that has been added
140
    virtual int addZone(const std::string& name);
141

JINMEI Tatuya's avatar
JINMEI Tatuya committed
142
143
    // Nothing special to add for this implementation (the base class
    // description is sufficient).
144
145
    virtual void deleteZone(int zone_id);

Jelte Jansen's avatar
Jelte Jansen committed
146
147
148
149
150
151
152
153
154
155
156
    /// \brief Look up all resource records for a name
    ///
    /// This implements the getRecords() method from DatabaseAccessor
    ///
    /// \exception SQLite3Error if there is an sqlite3 error when performing
    ///                        the query
    ///
    /// \param name the name to look up
    /// \param id the zone id, as returned by getZone()
    /// \param subdomains Match subdomains instead of the name.
    /// \return Iterator that contains all records with the given name
157
    virtual IteratorContextPtr getRecords(const std::string& name,
Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
158
159
                                          int id,
                                          bool subdomains = false) const;
160

Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
161
162
163
164
165
166
167
168
    /// \brief Look up NSEC3 records for the given hash
    ///
    /// This implements the getNSEC3Records of DatabaseAccessor.
    ///
    /// \todo Actually implement, currently throws NotImplemented.
    virtual IteratorContextPtr getNSEC3Records(const std::string& hash,
                                               int id) const;

Jelte Jansen's avatar
Jelte Jansen committed
169
170
171
172
173
174
175
176
177
    /// \brief Look up all resource records for a zone
    ///
    /// This implements the getRecords() method from DatabaseAccessor
    ///
    /// \exception SQLite3Error if there is an sqlite3 error when performing
    ///                        the query
    ///
    /// \param id the zone id, as returned by getZone()
    /// \return Iterator that contains all records in the given zone
178
    virtual IteratorContextPtr getAllRecords(int id) const;
179

Jelte Jansen's avatar
Jelte Jansen committed
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
    /// \brief Creates an iterator context for a set of differences.
    ///
    /// Implements the getDiffs() method from DatabaseAccessor
    ///
    /// \exception NoSuchSerial if either of the versions do not exist in
    ///           the difference table.
    /// \exception SQLite3Error if there is an sqlite3 error when performing
    ///           the query
    ///
    /// \param id The ID of the zone, returned from getZone().
    /// \param start The SOA serial number of the version of the zone from
    ///       which the difference sequence should start.
    /// \param end The SOA serial number of the version of the zone at which
    ///       the difference sequence should end.
    ///
    /// \return Iterator containing difference records.
196
197
    virtual IteratorContextPtr
    getDiffs(int id, uint32_t start, uint32_t end) const;
198
199


200
201
202
    virtual std::pair<bool, int> startUpdateZone(const std::string& zone_name,
                                                 bool replace);

203
204
    virtual void startTransaction();

JINMEI Tatuya's avatar
JINMEI Tatuya committed
205
    /// \note we are quite impatient here: it's quite possible that the COMMIT
206
207
208
209
210
    /// fails due to other process performing SELECT on the same database
    /// (consider the case where COMMIT is done by xfrin or dynamic update
    /// server while an authoritative server is busy reading the DB).
    /// In a future version we should probably need to introduce some retry
    /// attempt and/or increase timeout before giving up the COMMIT, even
JINMEI Tatuya's avatar
JINMEI Tatuya committed
211
212
    /// if it still doesn't guarantee 100% success.  Right now this
    /// implementation throws a \c DataSourceError exception in such a case.
213
    virtual void commit();
214

JINMEI Tatuya's avatar
JINMEI Tatuya committed
215
216
217
218
219
220
    /// \note In SQLite3 rollback can fail if there's another unfinished
    /// statement is performed for the same database structure.
    /// Although it's not expected to happen in our expected usage, it's not
    /// guaranteed to be prevented at the API level.  If it ever happens, this
    /// method throws a \c DataSourceError exception.  It should be
    /// considered a bug of the higher level application program.
221
    virtual void rollback();
222

223
224
    virtual void addRecordToZone(
        const std::string (&columns)[ADD_COLUMN_COUNT]);
225

226
    virtual void addNSEC3RecordToZone(
227
228
        const std::string (&columns)[ADD_NSEC3_COLUMN_COUNT]);

229
230
    virtual void deleteRecordInZone(
        const std::string (&params)[DEL_PARAM_COUNT]);
231

232
    virtual void deleteNSEC3RecordInZone(
233
234
        const std::string (&params)[DEL_PARAM_COUNT]);

235
236
237
    /// This derived version of the method prepares an SQLite3 statement
    /// for adding the diff first time it's called, and if it fails throws
    // an \c SQLite3Error exception.
238
239
240
241
    virtual void addRecordDiff(
        int zone_id, uint32_t serial, DiffOperation operation,
        const std::string (&params)[DIFF_PARAM_COUNT]);

242
243
244
245
246
247
    /// The SQLite3 implementation of this method returns a string starting
    /// with a fixed prefix of "sqlite3_" followed by the DB file name
    /// removing any path name.  For example, for the DB file
    /// /somewhere/in/the/system/bind10.sqlite3, this method will return
    /// "sqlite3_bind10.sqlite3".
    virtual const std::string& getDBName() const { return (database_name_); }
248

249
    /// \brief Concrete implementation of the pure virtual method
250
    virtual std::string findPreviousName(int zone_id, const std::string& rname)
251
252
        const;

253
254
255
256
257
    /// \brief Conrete implemantion of the pure virtual method of
    /// DatabaseAccessor
    virtual std::string findPreviousNSEC3Hash(int zone_id,
                                              const std::string& hash) const;

258
private:
259
    /// \brief Private database data
260
    boost::scoped_ptr<SQLite3Parameters> dbparameters_;
261
262
    /// \brief The filename of the DB (necessary for clone())
    const std::string filename_;
263
    /// \brief The class for which the queries are done
264
    const std::string class_;
265
266
267
    /// \brief Database name
    const std::string database_name_;

268
    /// \brief Opens the database
269
    void open(const std::string& filename);
270
    /// \brief Closes the database
271
    void close();
272
273

    /// \brief SQLite3 implementation of IteratorContext for all records
274
275
    class Context;
    friend class Context;
276
277
278
    /// \brief SQLite3 implementation of IteratorContext for differences
    class DiffContext;
    friend class DiffContext;
279
280
};

281
282
283
284
285
286
287
/// \brief Creates an instance of the SQlite3 datasource client
///
/// Currently the configuration passed here must be a MapElement, containing
/// one item called "database_file", whose value is a string
///
/// This configuration setup is currently under discussion and will change in
/// the near future.
288
289
290
291
292
293
///
/// \param config The configuration for the datasource instance
/// \param error This string will be set to an error message if an error occurs
///              during initialization
/// \return An instance of the sqlite3 datasource client, or NULL if there was
///         an error
294
295
extern "C" DataSourceClient* createInstance(isc::data::ConstElementPtr config,
                                            std::string& error);
296

297
/// \brief Destroy the instance created by createInstance()
298
299
extern "C" void destroyInstance(DataSourceClient* instance);

300
301
302
}
}

303
#endif  // DATASRC_SQLITE3_ACCESSOR_H
304
305
306
307

// Local Variables:
// mode: c++
// End: