Branch data Line data Source code
1 : : // Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
2 : : //
3 : : // Permission to use, copy, modify, and/or distribute this software for any
4 : : // purpose with or without fee is hereby granted, provided that the above
5 : : // copyright notice and this permission notice appear in all copies.
6 : : //
7 : : // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
8 : : // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
9 : : // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
10 : : // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
11 : : // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
12 : : // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
13 : : // PERFORMANCE OF THIS SOFTWARE.
14 : :
15 : :
16 : : #ifndef __DATASRC_SQLITE3_ACCESSOR_H
17 : : #define __DATASRC_SQLITE3_ACCESSOR_H
18 : :
19 : : #include <datasrc/database.h>
20 : : #include <datasrc/data_source.h>
21 : :
22 : : #include <exceptions/exceptions.h>
23 : :
24 : : #include <boost/enable_shared_from_this.hpp>
25 : : #include <boost/scoped_ptr.hpp>
26 : : #include <string>
27 : :
28 : : #include <cc/data.h>
29 : :
30 : : namespace isc {
31 : : namespace dns {
32 : : class RRClass;
33 : : }
34 : :
35 : : namespace datasrc {
36 : :
37 : : /**
38 : : * \brief Low-level database error
39 : : *
40 : : * This exception is thrown when the SQLite library complains about something.
41 : : * It might mean corrupt database file, invalid request or that something is
42 : : * rotten in the library.
43 : : */
44 : 5 : class SQLite3Error : public DataSourceError {
45 : : public:
46 : 5 : SQLite3Error(const char* file, size_t line, const char* what) :
47 : 5 : DataSourceError(file, line, what) {}
48 : : };
49 : :
50 : 4 : class IncompatibleDbVersion : public Exception {
51 : : public:
52 : : IncompatibleDbVersion(const char* file, size_t line, const char* what) :
53 [ + - ]: 2 : isc::Exception(file, line, what) {}
54 : : };
55 : :
56 : : /**
57 : : * \brief Too Much Data
58 : : *
59 : : * Thrown if a query expecting a certain number of rows back returned too
60 : : * many rows.
61 : : */
62 : 0 : class TooMuchData : public DataSourceError {
63 : : public:
64 : : TooMuchData(const char* file, size_t line, const char* what) :
65 [ # # ]: 0 : DataSourceError(file, line, what) {}
66 : : };
67 : :
68 : : /**
69 : : * \brief Too Little Data
70 : : *
71 : : * Thrown if a query expecting a certain number of rows back returned too
72 : : * few rows (including none).
73 : : */
74 : 8 : class TooLittleData : public DataSourceError {
75 : : public:
76 : : TooLittleData(const char* file, size_t line, const char* what) :
77 [ + - ]: 8 : DataSourceError(file, line, what) {}
78 : : };
79 : :
80 : : struct SQLite3Parameters;
81 : :
82 : : /**
83 : : * \brief Concrete implementation of DatabaseAccessor for SQLite3 databases
84 : : *
85 : : * This opens one database file with our schema and serves data from there.
86 : : * According to the design, it doesn't interpret the data in any way, it just
87 : : * provides unified access to the DB.
88 : : */
89 : : class SQLite3Accessor : public DatabaseAccessor,
90 : : public boost::enable_shared_from_this<SQLite3Accessor> {
91 : : public:
92 : : /**
93 : : * \brief Constructor
94 : : *
95 : : * This opens the database and becomes ready to serve data from there.
96 : : *
97 : : * \exception SQLite3Error will be thrown if the given database file
98 : : * doesn't work (it is broken, doesn't exist and can't be created, etc).
99 : : *
100 : : * \param filename The database file to be used.
101 : : * \param rrclass Textual representation of RR class ("IN", "CH", etc),
102 : : * specifying which class of data it should serve (while the database
103 : : * file can contain multiple classes of data, a single accessor can
104 : : * work with only one class).
105 : : */
106 : : SQLite3Accessor(const std::string& filename, const std::string& rrclass);
107 : :
108 : : /**
109 : : * \brief Destructor
110 : : *
111 : : * Closes the database.
112 : : */
113 : : ~SQLite3Accessor();
114 : :
115 : : /// This implementation internally opens a new sqlite3 database for the
116 : : /// same file name specified in the constructor of the original accessor.
117 : : virtual boost::shared_ptr<DatabaseAccessor> clone();
118 : :
119 : : /**
120 : : * \brief Look up a zone
121 : : *
122 : : * This implements the getZone from DatabaseAccessor and looks up a zone
123 : : * in the data. It looks for a zone with the exact given origin and class
124 : : * passed to the constructor.
125 : : *
126 : : * \exception SQLite3Error if something about the database is broken.
127 : : *
128 : : * \param name The (fully qualified) domain name of zone to look up
129 : : * \return The pair contains if the lookup was successful in the first
130 : : * element and the zone id in the second if it was.
131 : : */
132 : : virtual std::pair<bool, int> getZone(const std::string& name) const;
133 : :
134 : : /** \brief Look up all resource records for a name
135 : : *
136 : : * This implements the getRecords() method from DatabaseAccessor
137 : : *
138 : : * \exception SQLite3Error if there is an sqlite3 error when performing
139 : : * the query
140 : : *
141 : : * \param name the name to look up
142 : : * \param id the zone id, as returned by getZone()
143 : : * \param subdomains Match subdomains instead of the name.
144 : : * \return Iterator that contains all records with the given name
145 : : */
146 : : virtual IteratorContextPtr getRecords(const std::string& name,
147 : : int id,
148 : : bool subdomains = false) const;
149 : :
150 : : /// \brief Look up NSEC3 records for the given hash
151 : : ///
152 : : /// This implements the getNSEC3Records of DatabaseAccessor.
153 : : ///
154 : : /// \todo Actually implement, currently throws NotImplemented.
155 : : virtual IteratorContextPtr getNSEC3Records(const std::string& hash,
156 : : int id) const;
157 : :
158 : : /** \brief Look up all resource records for a zone
159 : : *
160 : : * This implements the getRecords() method from DatabaseAccessor
161 : : *
162 : : * \exception SQLite3Error if there is an sqlite3 error when performing
163 : : * the query
164 : : *
165 : : * \param id the zone id, as returned by getZone()
166 : : * \return Iterator that contains all records in the given zone
167 : : */
168 : : virtual IteratorContextPtr getAllRecords(int id) const;
169 : :
170 : : /** \brief Creates an iterator context for a set of differences.
171 : : *
172 : : * Implements the getDiffs() method from DatabaseAccessor
173 : : *
174 : : * \exception NoSuchSerial if either of the versions do not exist in
175 : : * the difference table.
176 : : * \exception SQLite3Error if there is an sqlite3 error when performing
177 : : * the query
178 : : *
179 : : * \param id The ID of the zone, returned from getZone().
180 : : * \param start The SOA serial number of the version of the zone from
181 : : * which the difference sequence should start.
182 : : * \param end The SOA serial number of the version of the zone at which
183 : : * the difference sequence should end.
184 : : *
185 : : * \return Iterator containing difference records.
186 : : */
187 : : virtual IteratorContextPtr
188 : : getDiffs(int id, uint32_t start, uint32_t end) const;
189 : :
190 : :
191 : : virtual std::pair<bool, int> startUpdateZone(const std::string& zone_name,
192 : : bool replace);
193 : :
194 : : virtual void startTransaction();
195 : :
196 : : /// \note we are quite impatient here: it's quite possible that the COMMIT
197 : : /// fails due to other process performing SELECT on the same database
198 : : /// (consider the case where COMMIT is done by xfrin or dynamic update
199 : : /// server while an authoritative server is busy reading the DB).
200 : : /// In a future version we should probably need to introduce some retry
201 : : /// attempt and/or increase timeout before giving up the COMMIT, even
202 : : /// if it still doesn't guarantee 100% success. Right now this
203 : : /// implementation throws a \c DataSourceError exception in such a case.
204 : : virtual void commit();
205 : :
206 : : /// \note In SQLite3 rollback can fail if there's another unfinished
207 : : /// statement is performed for the same database structure.
208 : : /// Although it's not expected to happen in our expected usage, it's not
209 : : /// guaranteed to be prevented at the API level. If it ever happens, this
210 : : /// method throws a \c DataSourceError exception. It should be
211 : : /// considered a bug of the higher level application program.
212 : : virtual void rollback();
213 : :
214 : : virtual void addRecordToZone(
215 : : const std::string (&columns)[ADD_COLUMN_COUNT]);
216 : :
217 : : virtual void addNSEC3RecordToZone(
218 : : const std::string (&columns)[ADD_NSEC3_COLUMN_COUNT]);
219 : :
220 : : virtual void deleteRecordInZone(
221 : : const std::string (¶ms)[DEL_PARAM_COUNT]);
222 : :
223 : : virtual void deleteNSEC3RecordInZone(
224 : : const std::string (¶ms)[DEL_PARAM_COUNT]);
225 : :
226 : : /// This derived version of the method prepares an SQLite3 statement
227 : : /// for adding the diff first time it's called, and if it fails throws
228 : : // an \c SQLite3Error exception.
229 : : virtual void addRecordDiff(
230 : : int zone_id, uint32_t serial, DiffOperation operation,
231 : : const std::string (¶ms)[DIFF_PARAM_COUNT]);
232 : :
233 : : /// The SQLite3 implementation of this method returns a string starting
234 : : /// with a fixed prefix of "sqlite3_" followed by the DB file name
235 : : /// removing any path name. For example, for the DB file
236 : : /// /somewhere/in/the/system/bind10.sqlite3, this method will return
237 : : /// "sqlite3_bind10.sqlite3".
238 : 1860 : virtual const std::string& getDBName() const { return (database_name_); }
239 : :
240 : : /// \brief Concrete implementation of the pure virtual method
241 : : virtual std::string findPreviousName(int zone_id, const std::string& rname)
242 : : const;
243 : :
244 : : /// \brief Conrete implemantion of the pure virtual method of
245 : : /// DatabaseAccessor
246 : : virtual std::string findPreviousNSEC3Hash(int zone_id,
247 : : const std::string& hash) const;
248 : :
249 : : private:
250 : : /// \brief Private database data
251 : : boost::scoped_ptr<SQLite3Parameters> dbparameters_;
252 : : /// \brief The filename of the DB (necessary for clone())
253 : : const std::string filename_;
254 : : /// \brief The class for which the queries are done
255 : : const std::string class_;
256 : : /// \brief Database name
257 : : const std::string database_name_;
258 : :
259 : : /// \brief Opens the database
260 : : void open(const std::string& filename);
261 : : /// \brief Closes the database
262 : : void close();
263 : :
264 : : /// \brief SQLite3 implementation of IteratorContext for all records
265 : : class Context;
266 : : friend class Context;
267 : : /// \brief SQLite3 implementation of IteratorContext for differences
268 : : class DiffContext;
269 : : friend class DiffContext;
270 : : };
271 : :
272 : : /// \brief Creates an instance of the SQlite3 datasource client
273 : : ///
274 : : /// Currently the configuration passed here must be a MapElement, containing
275 : : /// one item called "database_file", whose value is a string
276 : : ///
277 : : /// This configuration setup is currently under discussion and will change in
278 : : /// the near future.
279 : : ///
280 : : /// \param config The configuration for the datasource instance
281 : : /// \param error This string will be set to an error message if an error occurs
282 : : /// during initialization
283 : : /// \return An instance of the sqlite3 datasource client, or NULL if there was
284 : : /// an error
285 : : extern "C" DataSourceClient* createInstance(isc::data::ConstElementPtr config,
286 : : std::string& error);
287 : :
288 : : /// \brief Destroy the instance created by createInstance()
289 : : extern "C" void destroyInstance(DataSourceClient* instance);
290 : :
291 : : }
292 : : }
293 : :
294 : : #endif // __DATASRC_SQLITE3_CONNECTION_H
295 : :
296 : : // Local Variables:
297 : : // mode: c++
298 : : // End:
|