sqlite3_accessor.h 10.5 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
20

#include <datasrc/database.h>

21
22
#include <exceptions/exceptions.h>

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

27
28
#include <cc/data.h>

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

34
35
namespace datasrc {

36
37
38
39
40
41
42
/**
 * \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.
 */
43
class SQLite3Error : public Exception {
44
public:
45
46
47
    SQLite3Error(const char* file, size_t line, const char* what) :
        isc::Exception(file, line, what) {}
};
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
/**
 * \brief Too Much Data
 *
 * Thrown if a query expecting a certain number of rows back returned too
 * many rows.
 */
class TooMuchData : public Exception {
public:
    TooMuchData(const char* file, size_t line, const char* what) :
        isc::Exception(file, line, what) {}
};

/**
 * \brief Too Little Data
 *
 * Thrown if a query expecting a certain number of rows back returned too
 * few rows (including none).
 */
class TooLittleData : public Exception {
public:
    TooLittleData(const char* file, size_t line, const char* what) :
        isc::Exception(file, line, what) {}
};

73
74
75
/**
 * \brief No such serial number when obtaining difference iterator
 *
76
77
 * Thrown if either the zone/start version or zone/end version combination
 * does not exist in the differences table.
78
79
80
81
82
83
84
 */
class NoSuchSerial : public Exception {
public:
    NoSuchSerial(const char* file, size_t line, const char* what) :
        isc::Exception(file, line, what) {}
};

85

86
87
struct SQLite3Parameters;

88
/**
89
 * \brief Concrete implementation of DatabaseAccessor for SQLite3 databases
90
91
92
93
94
 *
 * 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.
 */
95
96
class SQLite3Accessor : public DatabaseAccessor,
    public boost::enable_shared_from_this<SQLite3Accessor> {
97
public:
98
99
100
101
102
    /**
     * \brief Constructor
     *
     * This opens the database and becomes ready to serve data from there.
     *
103
104
     * \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).
105
     *
106
     * \param filename The database file to be used.
107
108
109
110
     * \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).
111
112
113
     */
    SQLite3Accessor(const std::string& filename, const std::string& rrclass);

114
115
116
117
118
    /**
     * \brief Destructor
     *
     * Closes the database.
     */
119
    ~SQLite3Accessor();
Jelte Jansen's avatar
Jelte Jansen committed
120

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

125
126
127
    /**
     * \brief Look up a zone
     *
128
     * This implements the getZone from DatabaseAccessor and looks up a zone
129
130
131
     * in the data. It looks for a zone with the exact given origin and class
     * passed to the constructor.
     *
132
     * \exception SQLite3Error if something about the database is broken.
133
     *
134
     * \param name The (fully qualified) domain name of zone to look up
135
136
137
     * \return The pair contains if the lookup was successful in the first
     *     element and the zone id in the second if it was.
     */
138
    virtual std::pair<bool, int> getZone(const std::string& name) const;
Jelte Jansen's avatar
Jelte Jansen committed
139

Jelte Jansen's avatar
Jelte Jansen committed
140
141
142
143
144
145
146
147
148
    /** \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()
149
     * \param subdomains Match subdomains instead of the name.
Jelte Jansen's avatar
Jelte Jansen committed
150
151
     * \return Iterator that contains all records with the given name
     */
152
    virtual IteratorContextPtr getRecords(const std::string& name,
Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
153
154
                                          int id,
                                          bool subdomains = false) const;
155

Jelte Jansen's avatar
Jelte Jansen committed
156
157
158
159
160
161
162
163
164
165
    /** \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
     */
166
    virtual IteratorContextPtr getAllRecords(int id) const;
167

168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
    /** \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.
     */
185
186
    virtual IteratorContextPtr
    getDiffs(int id, uint32_t start, uint32_t end) const;
187
188


189
190
191
    virtual std::pair<bool, int> startUpdateZone(const std::string& zone_name,
                                                 bool replace);

192
193
    virtual void startTransaction();

JINMEI Tatuya's avatar
JINMEI Tatuya committed
194
    /// \note we are quite impatient here: it's quite possible that the COMMIT
195
196
197
198
199
    /// 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
200
201
    /// if it still doesn't guarantee 100% success.  Right now this
    /// implementation throws a \c DataSourceError exception in such a case.
202
    virtual void commit();
203

JINMEI Tatuya's avatar
JINMEI Tatuya committed
204
205
206
207
208
209
    /// \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.
210
    virtual void rollback();
211

212
213
    virtual void addRecordToZone(
        const std::string (&columns)[ADD_COLUMN_COUNT]);
214

215
216
    virtual void deleteRecordInZone(
        const std::string (&params)[DEL_PARAM_COUNT]);
217

218
219
220
    /// 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.
221
222
223
224
225
    virtual void addRecordDiff(
        int zone_id, uint32_t serial, DiffOperation operation,
        const std::string (&params)[DIFF_PARAM_COUNT]);

    // A short term method for tests until we implement more complete
226
227
    // API to retrieve diffs.  It returns all records of the diffs table
    // whose zone_id column is identical to the given value.
228
229
    std::vector<std::vector<std::string> > getRecordDiff(int zone_id);

230
231
232
233
234
235
    /// 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_); }
236

237
    /// \brief Concrete implementation of the pure virtual method
238
    virtual std::string findPreviousName(int zone_id, const std::string& rname)
239
240
        const;

241
private:
242
    /// \brief Private database data
243
    boost::scoped_ptr<SQLite3Parameters> dbparameters_;
244
245
    /// \brief The filename of the DB (necessary for clone())
    const std::string filename_;
246
    /// \brief The class for which the queries are done
247
    const std::string class_;
248
249
250
    /// \brief Database name
    const std::string database_name_;

251
    /// \brief Opens the database
252
    void open(const std::string& filename);
253
    /// \brief Closes the database
254
    void close();
255
256

    /// \brief SQLite3 implementation of IteratorContext for all records
257
258
    class Context;
    friend class Context;
259
260
261
    /// \brief SQLite3 implementation of IteratorContext for differences
    class DiffContext;
    friend class DiffContext;
262
263
};

264
265
266
267
268
269
270
/// \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.
271
272
273
274
275
276
///
/// \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
277
278
extern "C" DataSourceClient* createInstance(isc::data::ConstElementPtr config,
                                            std::string& error);
279

280
/// \brief Destroy the instance created by createInstance()
281
282
extern "C" void destroyInstance(DataSourceClient* instance);

283
284
285
}
}

286
287
288
289
290
#endif  // __DATASRC_SQLITE3_CONNECTION_H

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