LCOV - code coverage report
Current view: top level - datasrc - sqlite3_accessor.cc (source / functions) Hit Total Coverage
Test: report.info Lines: 406 447 90.8 %
Date: 2012-05-15 Functions: 57 59 96.6 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 327 826 39.6 %

           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                 :            : #include <sqlite3.h>
      16                 :            : 
      17                 :            : #include <string>
      18                 :            : #include <utility>
      19                 :            : #include <vector>
      20                 :            : 
      21                 :            : #include <exceptions/exceptions.h>
      22                 :            : 
      23                 :            : #include <datasrc/sqlite3_accessor.h>
      24                 :            : #include <datasrc/logger.h>
      25                 :            : #include <datasrc/data_source.h>
      26                 :            : #include <datasrc/factory.h>
      27                 :            : #include <datasrc/database.h>
      28                 :            : #include <util/filename.h>
      29                 :            : 
      30                 :            : using namespace std;
      31                 :            : using namespace isc::data;
      32                 :            : 
      33                 :            : namespace {
      34                 :            : // Expected schema.  The major version must match else there is an error.  If
      35                 :            : // the minor version of the database is less than this, a warning is output.
      36                 :            : //
      37                 :            : // It is assumed that a program written to run on m.n of the database will run
      38                 :            : // with a database version m.p, where p is any number.  However, if p < n,
      39                 :            : // we assume that the database structure was upgraded for some reason, and that
      40                 :            : // some advantage may result if the database is upgraded. Conversely, if p > n,
      41                 :            : // The database is at a later version than the program was written for and the
      42                 :            : // program may not be taking advantage of features (possibly performance
      43                 :            : // improvements) added to the database.
      44                 :            : const int SQLITE_SCHEMA_MAJOR_VERSION = 2;
      45                 :            : const int SQLITE_SCHEMA_MINOR_VERSION = 0;
      46                 :            : }
      47                 :            : 
      48                 :            : namespace isc {
      49                 :            : namespace datasrc {
      50                 :            : 
      51                 :            : // The following enum and char* array define the SQL statements commonly
      52                 :            : // used in this implementation.  Corresponding prepared statements (of
      53                 :            : // type sqlite3_stmt*) are maintained in the statements_ array of the
      54                 :            : // SQLite3Parameters structure.
      55                 :            : 
      56                 :            : enum StatementID {
      57                 :            :     ZONE = 0,
      58                 :            :     ANY = 1,
      59                 :            :     ANY_SUB = 2,
      60                 :            :     BEGIN = 3,
      61                 :            :     COMMIT = 4,
      62                 :            :     ROLLBACK = 5,
      63                 :            :     DEL_ZONE_RECORDS = 6,
      64                 :            :     ADD_RECORD = 7,
      65                 :            :     DEL_RECORD = 8,
      66                 :            :     ITERATE = 9,
      67                 :            :     FIND_PREVIOUS = 10,
      68                 :            :     ADD_RECORD_DIFF = 11,
      69                 :            :     LOW_DIFF_ID = 12,
      70                 :            :     HIGH_DIFF_ID = 13,
      71                 :            :     DIFF_RECS = 14,
      72                 :            :     NSEC3 = 15,
      73                 :            :     NSEC3_PREVIOUS = 16,
      74                 :            :     NSEC3_LAST = 17,
      75                 :            :     ADD_NSEC3_RECORD = 18,
      76                 :            :     DEL_ZONE_NSEC3_RECORDS = 19,
      77                 :            :     DEL_NSEC3_RECORD = 20,
      78                 :            :     NUM_STATEMENTS = 21
      79                 :            : };
      80                 :            : 
      81                 :            : const char* const text_statements[NUM_STATEMENTS] = {
      82                 :            :     // note for ANY and ITERATE: the order of the SELECT values is
      83                 :            :     // specifically chosen to match the enum values in RecordColumns
      84                 :            :     "SELECT id FROM zones WHERE name=?1 AND rdclass = ?2", // ZONE
      85                 :            :     "SELECT rdtype, ttl, sigtype, rdata FROM records "     // ANY
      86                 :            :         "WHERE zone_id=?1 AND name=?2",
      87                 :            :     "SELECT rdtype, ttl, sigtype, rdata " // ANY_SUB
      88                 :            :         "FROM records WHERE zone_id=?1 AND name LIKE (\"%.\" || ?2)",
      89                 :            :     "BEGIN",                    // BEGIN
      90                 :            :     "COMMIT",                   // COMMIT
      91                 :            :     "ROLLBACK",                 // ROLLBACK
      92                 :            :     "DELETE FROM records WHERE zone_id=?1", // DEL_ZONE_RECORDS
      93                 :            :     "INSERT INTO records "      // ADD_RECORD
      94                 :            :         "(zone_id, name, rname, ttl, rdtype, sigtype, rdata) "
      95                 :            :         "VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)",
      96                 :            :     "DELETE FROM records WHERE zone_id=?1 AND name=?2 " // DEL_RECORD
      97                 :            :         "AND rdtype=?3 AND rdata=?4",
      98                 :            :     // The following iterates the whole zone. As the NSEC3 records
      99                 :            :     // (and corresponding RRSIGs) live in separate table, we need to
     100                 :            :     // take both of them. As the RRSIGs are for NSEC3s in the other
     101                 :            :     // table, we can easily hardcode the sigtype.
     102                 :            :     //
     103                 :            :     // The extra column is so we can order it by rname. This is to
     104                 :            :     // preserve the previous order, mostly for tests.
     105                 :            :     // TODO: Is it possible to get rid of the ordering?
     106                 :            :     "SELECT rdtype, ttl, sigtype, rdata, name, rname FROM records " // ITERATE
     107                 :            :         "WHERE zone_id = ?1 "
     108                 :            :         "UNION "
     109                 :            :         "SELECT rdtype, ttl, \"NSEC3\", rdata, owner, owner FROM nsec3 "
     110                 :            :         "WHERE zone_id = ?1 ORDER by rname, rdtype",
     111                 :            :     /*
     112                 :            :      * This one looks for previous name with NSEC record. It is done by
     113                 :            :      * using the reversed name. The NSEC is checked because we need to
     114                 :            :      * skip glue data, which don't have the NSEC.
     115                 :            :      */
     116                 :            :     "SELECT name FROM records " // FIND_PREVIOUS
     117                 :            :         "WHERE zone_id=?1 AND rdtype = 'NSEC' AND "
     118                 :            :         "rname < ?2 ORDER BY rname DESC LIMIT 1",
     119                 :            :     "INSERT INTO diffs "        // ADD_RECORD_DIFF
     120                 :            :         "(zone_id, version, operation, name, rrtype, ttl, rdata) "
     121                 :            :         "VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)",
     122                 :            : 
     123                 :            :     // Two statements to select the lowest ID and highest ID in a set of
     124                 :            :     // differences.
     125                 :            :     "SELECT id FROM diffs "     // LOW_DIFF_ID
     126                 :            :         "WHERE zone_id=?1 AND version=?2 and OPERATION=?3 "
     127                 :            :         "ORDER BY id ASC LIMIT 1",
     128                 :            :     "SELECT id FROM diffs "     // HIGH_DIFF_ID
     129                 :            :         "WHERE zone_id=?1 AND version=?2 and OPERATION=?3 "
     130                 :            :         "ORDER BY id DESC LIMIT 1",
     131                 :            : 
     132                 :            :     // In the next statement, note the redundant ID.  This is to ensure
     133                 :            :     // that the columns match the column IDs passed to the iterator
     134                 :            :     "SELECT rrtype, ttl, id, rdata, name FROM diffs "   // DIFF_RECS
     135                 :            :         "WHERE zone_id=?1 AND id>=?2 and id<=?3 "
     136                 :            :         "ORDER BY id ASC",
     137                 :            : 
     138                 :            :     // NSEC3: Query to get the NSEC3 records
     139                 :            :     //
     140                 :            :     // The "1" in SELECT is for positioning the rdata column to the
     141                 :            :     // expected position, so we can reuse the same code as for other
     142                 :            :     // lookups.
     143                 :            :     "SELECT rdtype, ttl, 1, rdata FROM nsec3 WHERE zone_id=?1 AND "
     144                 :            :         "hash=?2",
     145                 :            :     // NSEC3_PREVIOUS: For getting the previous NSEC3 hash
     146                 :            :     "SELECT DISTINCT hash FROM nsec3 WHERE zone_id=?1 AND hash < ?2 "
     147                 :            :         "ORDER BY hash DESC LIMIT 1",
     148                 :            :     // NSEC3_LAST: And for wrap-around
     149                 :            :     "SELECT DISTINCT hash FROM nsec3 WHERE zone_id=?1 "
     150                 :            :         "ORDER BY hash DESC LIMIT 1",
     151                 :            :     // ADD_NSEC3_RECORD: Add NSEC3-related (NSEC3 or NSEC3-covering RRSIG) RR
     152                 :            :     "INSERT INTO nsec3 (zone_id, hash, owner, ttl, rdtype, rdata) "
     153                 :            :     "VALUES (?1, ?2, ?3, ?4, ?5, ?6)",
     154                 :            :     // DEL_ZONE_NSEC3_RECORDS: delete all NSEC3-related records from the zone
     155                 :            :     "DELETE FROM nsec3 WHERE zone_id=?1",
     156                 :            :     // DEL_NSEC3_RECORD: delete specified NSEC3-related records
     157                 :            :     "DELETE FROM nsec3 WHERE zone_id=?1 AND hash=?2 "
     158                 :            :     "AND rdtype=?3 AND rdata=?4"
     159                 :            : };
     160                 :            : 
     161                 :       1337 : struct SQLite3Parameters {
     162                 :            :     SQLite3Parameters() :
     163                 :            :         db_(NULL), major_version_(-1), minor_version_(-1),
     164                 :       1337 :         in_transaction(false), updating_zone(false), updated_zone_id(-1)
     165                 :            :     {
     166 [ +  + ][ +  + ]:      29414 :         for (int i = 0; i < NUM_STATEMENTS; ++i) {
                 [ +  + ]
     167                 :      28077 :             statements_[i] = NULL;
     168                 :            :         }
     169                 :            :     }
     170                 :            : 
     171                 :            :     // This method returns the specified ID of SQLITE3 statement.  If it's
     172                 :            :     // not yet prepared it internally creates a new one.  This way we can
     173                 :            :     // avoid preparing unnecessary statements and minimize the overhead.
     174                 :            :     sqlite3_stmt*
     175                 :      13289 :     getStatement(int id) {
     176         [ -  + ]:      13289 :         assert(id < NUM_STATEMENTS);
     177         [ +  + ]:      13289 :         if (statements_[id] == NULL) {
     178         [ -  + ]:       1240 :             assert(db_ != NULL);
     179                 :       1240 :             sqlite3_stmt* prepared = NULL;
     180         [ -  + ]:       1240 :             if (sqlite3_prepare_v2(db_, text_statements[id], -1, &prepared,
     181                 :       1240 :                                    NULL) != SQLITE_OK) {
     182 [ #  # ][ #  # ]:          0 :                 isc_throw(SQLite3Error, "Could not prepare SQLite statement: "
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     183                 :            :                           << text_statements[id] <<
     184                 :            :                           ": " << sqlite3_errmsg(db_));
     185                 :            :             }
     186                 :       1240 :             statements_[id] = prepared;
     187                 :            :         }
     188                 :      13289 :         return (statements_[id]);
     189                 :            :     }
     190                 :            : 
     191                 :            :     void
     192                 :        449 :     finalizeStatements() {
     193         [ +  + ]:       9878 :         for (int i = 0; i < NUM_STATEMENTS; ++i) {
     194         [ +  + ]:       9429 :             if (statements_[i] != NULL) {
     195                 :       1240 :                 sqlite3_finalize(statements_[i]);
     196                 :       1240 :                 statements_[i] = NULL;
     197                 :            :             }
     198                 :            :         }
     199                 :        449 :     }
     200                 :            : 
     201                 :            :     sqlite3* db_;
     202                 :            :     int major_version_;
     203                 :            :     int minor_version_;
     204                 :            :     bool in_transaction; // whether or not a transaction has been started
     205                 :            :     bool updating_zone;          // whether or not updating the zone
     206                 :            :     int updated_zone_id;        // valid only when in_transaction is true
     207                 :            :     string updated_zone_origin_; // ditto, and only needed to handle NSEC3s
     208                 :            : private:
     209                 :            :     // statements_ are private and must be accessed via getStatement() outside
     210                 :            :     // of this structure.
     211                 :            :     sqlite3_stmt* statements_[NUM_STATEMENTS];
     212                 :            : };
     213                 :            : 
     214                 :            : // This is a helper class to encapsulate the code logic of executing
     215                 :            : // a specific SQLite3 statement, ensuring the corresponding prepared
     216                 :            : // statement is always reset whether the execution is completed successfully
     217                 :            : // or it results in an exception.
     218                 :            : // Note that an object of this class is intended to be used for "ephemeral"
     219                 :            : // statement, which is completed with a single "step" (normally within a
     220                 :            : // single call to an SQLite3Database method).  In particular, it cannot be
     221                 :            : // used for "SELECT" variants, which generally expect multiple matching rows.
     222                 :            : //
     223                 :            : // The bindXXX methods are straightforward wrappers for the corresponding
     224                 :            : // sqlite3_bind_xxx functions that make bindings with the given parameters
     225                 :            : // on the statement maintained in this class.
     226                 :            : class StatementProcessor {
     227                 :            : public:
     228                 :            :     // desc will be used on failure in the what() message of the resulting
     229                 :            :     // DataSourceError exception.
     230                 :       8917 :     StatementProcessor(SQLite3Parameters& dbparameters, StatementID stmt_id,
     231                 :            :                        const char* desc) :
     232                 :       8917 :         dbparameters_(dbparameters), stmt_(dbparameters.getStatement(stmt_id)),
     233                 :      17834 :         desc_(desc)
     234                 :            :     {
     235                 :       8917 :         sqlite3_clear_bindings(stmt_);
     236                 :       8917 :     }
     237                 :            : 
     238                 :       8917 :     ~StatementProcessor() {
     239                 :       8917 :         sqlite3_reset(stmt_);
     240                 :       8917 :     }
     241                 :            : 
     242                 :       9319 :     void bindInt(int index, int val) {
     243         [ -  + ]:       9319 :         if (sqlite3_bind_int(stmt_, index, val) != SQLITE_OK) {
     244 [ #  # ][ #  # ]:          0 :             isc_throw(DataSourceError,
         [ #  # ][ #  # ]
     245                 :            :                       "failed to bind SQLite3 parameter: " <<
     246                 :            :                       sqlite3_errmsg(dbparameters_.db_));
     247                 :            :         }
     248                 :       9319 :     }
     249                 :            : 
     250                 :        836 :     void bindInt64(int index, sqlite3_int64 val) {
     251         [ -  + ]:        836 :         if (sqlite3_bind_int64(stmt_, index, val) != SQLITE_OK) {
     252 [ #  # ][ #  # ]:          0 :             isc_throw(DataSourceError,
         [ #  # ][ #  # ]
     253                 :            :                       "failed to bind SQLite3 parameter: " <<
     254                 :            :                       sqlite3_errmsg(dbparameters_.db_));
     255                 :            :         }
     256                 :        836 :     }
     257                 :            : 
     258                 :            :     // For simplicity, we assume val is a NULL-terminated string, and the
     259                 :            :     // entire non NUL characters are to be bound.  The destructor parameter
     260                 :            :     // is normally either SQLITE_TRANSIENT or SQLITE_STATIC.
     261                 :      46509 :     void bindText(int index, const char* val, void(*destructor)(void*)) {
     262         [ -  + ]:      46509 :         if (sqlite3_bind_text(stmt_, index, val, -1, destructor)
     263                 :            :             != SQLITE_OK) {
     264 [ #  # ][ #  # ]:          0 :             isc_throw(DataSourceError, "failed to bind SQLite3 parameter: " <<
         [ #  # ][ #  # ]
     265                 :            :                       sqlite3_errmsg(dbparameters_.db_));
     266                 :            :         }
     267                 :      46509 :     }
     268                 :            : 
     269                 :       8917 :     void exec() {
     270         [ +  + ]:       8917 :         if (sqlite3_step(stmt_) != SQLITE_DONE) {
     271                 :          5 :             sqlite3_reset(stmt_);
     272 [ +  - ][ +  - ]:         10 :             isc_throw(DataSourceError, "failed to " << desc_ << ": " <<
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     273                 :            :                       sqlite3_errmsg(dbparameters_.db_));
     274                 :            :         }
     275                 :       8912 :     }
     276                 :            : 
     277                 :            : private:
     278                 :            :     SQLite3Parameters& dbparameters_;
     279                 :            :     sqlite3_stmt* stmt_;
     280                 :            :     const char* const desc_;
     281                 :            : };
     282                 :            : 
     283                 :        448 : SQLite3Accessor::SQLite3Accessor(const std::string& filename,
     284                 :            :                                  const string& rrclass) :
     285                 :            :     dbparameters_(new SQLite3Parameters),
     286                 :            :     filename_(filename),
     287                 :            :     class_(rrclass),
     288                 :            :     database_name_("sqlite3_" +
     289 [ +  - ][ +  - ]:       1351 :                    isc::util::Filename(filename).nameAndExtension())
                 [ +  - ]
     290                 :            : {
     291 [ +  - ][ +  - ]:        448 :     LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_SQLITE_NEWCONN);
         [ +  - ][ +  - ]
     292                 :            : 
     293         [ +  + ]:        448 :     open(filename);
     294                 :        441 : }
     295                 :            : 
     296                 :            : boost::shared_ptr<DatabaseAccessor>
     297                 :        138 : SQLite3Accessor::clone() {
     298                 :            :     return (boost::shared_ptr<DatabaseAccessor>(new SQLite3Accessor(filename_,
     299         [ +  - ]:        138 :                                                                     class_)));
     300                 :            : }
     301                 :            : 
     302                 :            : namespace {
     303                 :            : 
     304                 :            : // This is a helper class to initialize a Sqlite3 DB safely.  An object of
     305                 :            : // this class encapsulates all temporary resources that are necessary for
     306                 :            : // the initialization, and release them in the destructor.  Once everything
     307                 :            : // is properly initialized, the move() method moves the allocated resources
     308                 :            : // to the main object in an exception free manner.  This way, the main code
     309                 :            : // for the initialization can be exception safe, and can provide the strong
     310                 :            : // exception guarantee.
     311                 :        448 : class Initializer {
     312                 :            : public:
     313                 :        896 :     ~Initializer() {
     314         [ +  + ]:        448 :         if (params_.db_ != NULL) {
     315         [ +  - ]:          7 :             sqlite3_close(params_.db_);
     316                 :            :         }
     317                 :        448 :     }
     318                 :            :     void move(SQLite3Parameters* dst) {
     319                 :        441 :         *dst = params_;
     320                 :        441 :         params_ = SQLite3Parameters(); // clear everything
     321                 :            :     }
     322                 :            :     SQLite3Parameters params_;
     323                 :            : };
     324                 :            : 
     325                 :            : const char* const SCHEMA_LIST[] = {
     326                 :            :     "CREATE TABLE schema_version (version INTEGER NOT NULL, "
     327                 :            :         "minor INTEGER NOT NULL DEFAULT 0)",
     328                 :            :     "INSERT INTO schema_version VALUES (2, 0)",
     329                 :            :     "CREATE TABLE zones (id INTEGER PRIMARY KEY, "
     330                 :            :     "name TEXT NOT NULL COLLATE NOCASE, "
     331                 :            :     "rdclass TEXT NOT NULL COLLATE NOCASE DEFAULT 'IN', "
     332                 :            :     "dnssec BOOLEAN NOT NULL DEFAULT 0)",
     333                 :            :     "CREATE INDEX zones_byname ON zones (name)",
     334                 :            :     "CREATE TABLE records (id INTEGER PRIMARY KEY, "
     335                 :            :         "zone_id INTEGER NOT NULL, name TEXT NOT NULL COLLATE NOCASE, "
     336                 :            :         "rname TEXT NOT NULL COLLATE NOCASE, ttl INTEGER NOT NULL, "
     337                 :            :         "rdtype TEXT NOT NULL COLLATE NOCASE, sigtype TEXT COLLATE NOCASE, "
     338                 :            :         "rdata TEXT NOT NULL)",
     339                 :            :     "CREATE INDEX records_byname ON records (name)",
     340                 :            :     "CREATE INDEX records_byrname ON records (rname)",
     341                 :            :     // The next index is a tricky one.  It's necessary for
     342                 :            :     // FIND_PREVIOUS to use the index efficiently; since there's an
     343                 :            :     // "inequality", the rname column must be placed later.  records_byrname
     344                 :            :     // may not be sufficient especially when the zone is not signed (and
     345                 :            :     // defining a separate index for rdtype only doesn't work either; SQLite3
     346                 :            :     // would then create a temporary B-tree for "ORDER BY").
     347                 :            :     "CREATE INDEX records_bytype_and_rname ON records (rdtype, rname)",
     348                 :            :     "CREATE TABLE nsec3 (id INTEGER PRIMARY KEY, zone_id INTEGER NOT NULL, "
     349                 :            :         "hash TEXT NOT NULL COLLATE NOCASE, "
     350                 :            :         "owner TEXT NOT NULL COLLATE NOCASE, "
     351                 :            :         "ttl INTEGER NOT NULL, rdtype TEXT NOT NULL COLLATE NOCASE, "
     352                 :            :         "rdata TEXT NOT NULL)",
     353                 :            :     "CREATE INDEX nsec3_byhash ON nsec3 (hash)",
     354                 :            :     "CREATE TABLE diffs (id INTEGER PRIMARY KEY, "
     355                 :            :         "zone_id INTEGER NOT NULL, "
     356                 :            :         "version INTEGER NOT NULL, "
     357                 :            :         "operation INTEGER NOT NULL, "
     358                 :            :         "name TEXT NOT NULL COLLATE NOCASE, "
     359                 :            :         "rrtype TEXT NOT NULL COLLATE NOCASE, "
     360                 :            :         "ttl INTEGER NOT NULL, "
     361                 :            :         "rdata TEXT NOT NULL)",
     362                 :            :     NULL
     363                 :            : };
     364                 :            : 
     365                 :            : sqlite3_stmt*
     366                 :       1870 : prepare(sqlite3* const db, const char* const statement) {
     367                 :       1870 :     sqlite3_stmt* prepared = NULL;
     368         [ -  + ]:       1870 :     if (sqlite3_prepare_v2(db, statement, -1, &prepared, NULL) != SQLITE_OK) {
     369 [ #  # ][ #  # ]:          0 :         isc_throw(SQLite3Error, "Could not prepare SQLite statement: " <<
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     370                 :            :                   statement << ": " << sqlite3_errmsg(db));
     371                 :            :     }
     372                 :       1870 :     return (prepared);
     373                 :            : }
     374                 :            : 
     375                 :            : // small function to sleep for 0.1 seconds, needed when waiting for
     376                 :            : // exclusive database locks (which should only occur on startup, and only
     377                 :            : // when the database has not been created yet)
     378                 :         50 : void doSleep() {
     379                 :            :     struct timespec req;
     380                 :         50 :     req.tv_sec = 0;
     381                 :         50 :     req.tv_nsec = 100000000;
     382                 :         50 :     nanosleep(&req, NULL);
     383                 :         50 : }
     384                 :            : 
     385                 :            : // returns the schema version if the schema version table exists
     386                 :            : // returns -1 if it does not
     387                 :        897 : int checkSchemaVersionElement(sqlite3* db, const char* const query) {
     388                 :        897 :     sqlite3_stmt* prepared = NULL;
     389                 :            :     // At this point in time, the database might be exclusively locked, in
     390                 :            :     // which case even prepare() will return BUSY, so we may need to try a
     391                 :            :     // few times
     392         [ +  + ]:        947 :     for (size_t i = 0; i < 50; ++i) {
     393                 :        946 :         int rc = sqlite3_prepare_v2(db, query, -1, &prepared, NULL);
     394         [ +  + ]:        946 :         if (rc == SQLITE_ERROR) {
     395                 :            :             // this is the error that is returned when the table does not
     396                 :            :             // exist
     397                 :            :             return (-1);
     398         [ +  + ]:        936 :         } else if (rc == SQLITE_OK) {
     399                 :            :             break;
     400         [ -  + ]:         50 :         } else if (rc != SQLITE_BUSY || i == 50) {
     401 [ #  # ][ #  # ]:          0 :             isc_throw(SQLite3Error, "Unable to prepare version query: "
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     402                 :            :                         << rc << " " << sqlite3_errmsg(db));
     403                 :            :         }
     404                 :         50 :         doSleep();
     405                 :            :     }
     406         [ +  + ]:        887 :     if (sqlite3_step(prepared) != SQLITE_ROW) {
     407 [ +  - ][ +  - ]:          4 :         isc_throw(SQLite3Error,
         [ +  - ][ +  - ]
     408                 :            :                     "Unable to query version: " << sqlite3_errmsg(db));
     409                 :            :     }
     410                 :        885 :     int version = sqlite3_column_int(prepared, 0);
     411                 :        885 :     sqlite3_finalize(prepared);
     412                 :        895 :     return (version);
     413                 :            : }
     414                 :            : 
     415                 :            : // Returns the schema major and minor version numbers in a pair.
     416                 :            : // Returns (-1, -1) if the table does not exist, (1, 0) for a V1
     417                 :            : // database, and (n, m) for any other.
     418                 :        455 : pair<int, int> checkSchemaVersion(sqlite3* db) {
     419                 :            :     int major = checkSchemaVersionElement(db,
     420                 :        455 :         "SELECT version FROM schema_version");
     421         [ +  + ]:        453 :     if (major == -1) {
     422                 :            :         return (make_pair(-1, -1));
     423         [ +  + ]:        443 :     } else if (major == 1) {
     424                 :            :         return (make_pair(1, 0));
     425                 :            :     } else {
     426                 :            :         int minor = checkSchemaVersionElement(db,
     427                 :        442 :             "SELECT minor FROM schema_version");
     428                 :            :         return (make_pair(major, minor));
     429                 :            :     }
     430                 :            : }
     431                 :            : 
     432                 :            : // A helper class used in createDatabase() below so we manage the one shot
     433                 :            : // transaction safely.
     434                 :            : class ScopedTransaction {
     435                 :            : public:
     436                 :          5 :     ScopedTransaction(sqlite3* db) : db_(NULL) {
     437                 :            :         // try for 5 secs (50*0.1)
     438         [ +  - ]:          5 :         for (size_t i = 0; i < 50; ++i) {
     439                 :            :             const int rc = sqlite3_exec(db, "BEGIN EXCLUSIVE TRANSACTION",
     440                 :          5 :                                         NULL, NULL, NULL);
     441         [ -  + ]:          5 :             if (rc == SQLITE_OK) {
     442                 :            :                 break;
     443         [ #  # ]:          0 :             } else if (rc != SQLITE_BUSY || i == 50) {
     444 [ #  # ][ #  # ]:          0 :                 isc_throw(SQLite3Error, "Unable to acquire exclusive lock "
         [ #  # ][ #  # ]
     445                 :            :                           "for database creation: " << sqlite3_errmsg(db));
     446                 :            :             }
     447                 :          0 :             doSleep();
     448                 :            :         }
     449                 :            :         // Hold the DB pointer once we have successfully acquired the lock.
     450                 :          5 :         db_ = db;
     451                 :            :     }
     452                 :          5 :     ~ScopedTransaction() {
     453         [ -  + ]:          5 :         if (db_ != NULL) {
     454                 :            :             // Note: even rollback could fail in theory, but in that case
     455                 :            :             // we cannot do much for safe recovery anyway.  We could at least
     456                 :            :             // log the event, but for now don't even bother to do that, with
     457                 :            :             // the expectation that we'll soon stop creating the schema in this
     458                 :            :             // module.
     459                 :          0 :             sqlite3_exec(db_, "ROLLBACK", NULL, NULL, NULL);
     460                 :            :         }
     461                 :          5 :     }
     462                 :            :     void commit() {
     463 [ +  - ][ -  + ]:          5 :         if (sqlite3_exec(db_, "COMMIT TRANSACTION", NULL, NULL, NULL) !=
     464                 :            :             SQLITE_OK) {
     465 [ #  # ][ #  # ]:          0 :             isc_throw(SQLite3Error, "Unable to commit newly created database "
         [ #  # ][ #  # ]
                 [ #  # ]
     466                 :            :                       "schema: " << sqlite3_errmsg(db_));
     467                 :            :         }
     468                 :          5 :         db_ = NULL;
     469                 :            :     }
     470                 :            : 
     471                 :            : private:
     472                 :            :     sqlite3* db_;
     473                 :            : };
     474                 :            : 
     475                 :            : // return db version
     476                 :            : pair<int, int>
     477                 :          5 : createDatabase(sqlite3* db) {
     478                 :          5 :     logger.info(DATASRC_SQLITE_SETUP);
     479                 :            : 
     480                 :            :     // try to get an exclusive lock. Once that is obtained, do the version
     481                 :            :     // check *again*, just in case this process was racing another
     482                 :          5 :     ScopedTransaction trasaction(db);
     483         [ +  - ]:          5 :     pair<int, int> schema_version = checkSchemaVersion(db);
     484         [ +  - ]:          5 :     if (schema_version.first == -1) {
     485         [ +  + ]:         60 :         for (int i = 0; SCHEMA_LIST[i] != NULL; ++i) {
     486 [ +  - ][ -  + ]:         55 :             if (sqlite3_exec(db, SCHEMA_LIST[i], NULL, NULL, NULL) !=
     487                 :            :                 SQLITE_OK) {
     488 [ #  # ][ #  # ]:          0 :                 isc_throw(SQLite3Error,
         [ #  # ][ #  # ]
     489                 :            :                           "Failed to set up schema " << SCHEMA_LIST[i]);
     490                 :            :             }
     491                 :            :         }
     492                 :            :         trasaction.commit();
     493                 :            : 
     494                 :            :         // Return the version.  We query again to ensure that the only point
     495                 :            :         // in which the current schema version is defined is in the create
     496                 :            :         // statements.
     497         [ +  - ]:          5 :         schema_version = checkSchemaVersion(db);
     498                 :            :     }
     499                 :            : 
     500                 :          5 :     return (schema_version);
     501                 :            : }
     502                 :            : 
     503                 :            : void
     504                 :        445 : checkAndSetupSchema(Initializer* initializer) {
     505                 :        445 :     sqlite3* const db = initializer->params_.db_;
     506                 :            : 
     507                 :        445 :     pair<int, int> schema_version = checkSchemaVersion(db);
     508         [ +  + ]:        443 :     if (schema_version.first == -1) {
     509                 :          5 :         schema_version = createDatabase(db);
     510         [ +  + ]:        438 :     } else if (schema_version.first != SQLITE_SCHEMA_MAJOR_VERSION) {
     511         [ +  - ]:          4 :         LOG_ERROR(logger, DATASRC_SQLITE_INCOMPATIBLE_VERSION)
     512 [ +  - ][ +  - ]:          2 :             .arg(schema_version.first).arg(schema_version.second)
     513 [ +  - ][ +  - ]:          2 :             .arg(SQLITE_SCHEMA_MAJOR_VERSION).arg(SQLITE_SCHEMA_MINOR_VERSION);
     514 [ +  - ][ +  - ]:          4 :         isc_throw(IncompatibleDbVersion,
         [ +  - ][ +  - ]
     515                 :            :                   "incompatible SQLite3 database version: " <<
     516                 :            :                   schema_version.first << "." << schema_version.second);
     517         [ -  + ]:        436 :     } else if (schema_version.second < SQLITE_SCHEMA_MINOR_VERSION) {
     518         [ #  # ]:          0 :         LOG_WARN(logger, DATASRC_SQLITE_COMPATIBLE_VERSION)
     519 [ #  # ][ #  # ]:          0 :             .arg(schema_version.first).arg(schema_version.second)
     520 [ #  # ][ #  # ]:          0 :             .arg(SQLITE_SCHEMA_MAJOR_VERSION).arg(SQLITE_SCHEMA_MINOR_VERSION);
     521                 :            :     }
     522                 :            : 
     523                 :        441 :     initializer->params_.major_version_ = schema_version.first;
     524                 :        441 :     initializer->params_.minor_version_ = schema_version.second;
     525                 :        441 : }
     526                 :            : 
     527                 :            : }
     528                 :            : 
     529                 :            : void
     530                 :        448 : SQLite3Accessor::open(const std::string& name) {
     531         [ +  - ]:        896 :     LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_SQLITE_CONNOPEN).arg(name);
     532         [ -  + ]:        448 :     if (dbparameters_->db_ != NULL) {
     533                 :            :         // There shouldn't be a way to trigger this anyway
     534 [ #  # ][ #  # ]:          0 :         isc_throw(DataSourceError, "Duplicate SQLite open with " << name);
                 [ #  # ]
     535                 :            :     }
     536                 :            : 
     537                 :        448 :     Initializer initializer;
     538                 :            : 
     539 [ +  - ][ +  + ]:        448 :     if (sqlite3_open(name.c_str(), &initializer.params_.db_) != 0) {
     540 [ +  - ][ +  - ]:          6 :         isc_throw(SQLite3Error, "Cannot open SQLite database file: " << name);
         [ +  - ][ +  - ]
     541                 :            :     }
     542                 :            : 
     543         [ +  + ]:        445 :     checkAndSetupSchema(&initializer);
     544                 :        882 :     initializer.move(dbparameters_.get());
     545                 :        441 : }
     546                 :            : 
     547                 :        441 : SQLite3Accessor::~SQLite3Accessor() {
     548 [ +  - ][ +  - ]:        441 :     LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_SQLITE_DROPCONN);
         [ +  - ][ +  - ]
     549         [ +  - ]:        441 :     if (dbparameters_->db_ != NULL) {
     550         [ +  - ]:        441 :         close();
     551                 :            :     }
     552                 :        810 : }
     553                 :            : 
     554                 :            : void
     555                 :        441 : SQLite3Accessor::close(void) {
     556         [ +  - ]:        441 :     LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_SQLITE_CONNCLOSE);
     557         [ -  + ]:        441 :     if (dbparameters_->db_ == NULL) {
     558 [ #  # ][ #  # ]:          0 :         isc_throw(DataSourceError,
     559                 :            :                   "SQLite data source is being closed before open");
     560                 :            :     }
     561                 :            : 
     562                 :        441 :     dbparameters_->finalizeStatements();
     563                 :        441 :     sqlite3_close(dbparameters_->db_);
     564                 :        441 :     dbparameters_->db_ = NULL;
     565                 :        441 : }
     566                 :            : 
     567                 :            : std::pair<bool, int>
     568                 :        797 : SQLite3Accessor::getZone(const std::string& name) const {
     569                 :            :     int rc;
     570                 :        797 :     sqlite3_stmt* const stmt = dbparameters_->getStatement(ZONE);
     571                 :            : 
     572                 :            :     // Take the statement (simple SELECT id FROM zones WHERE...)
     573                 :            :     // and prepare it (bind the parameters to it)
     574                 :        797 :     sqlite3_reset(stmt);
     575                 :        797 :     rc = sqlite3_bind_text(stmt, 1, name.c_str(), -1, SQLITE_STATIC);
     576         [ -  + ]:        797 :     if (rc != SQLITE_OK) {
     577 [ #  # ][ #  # ]:          0 :         isc_throw(SQLite3Error, "Could not bind " << name <<
         [ #  # ][ #  # ]
     578                 :            :                   " to SQL statement (zone)");
     579                 :            :     }
     580                 :        797 :     rc = sqlite3_bind_text(stmt, 2, class_.c_str(), -1, SQLITE_STATIC);
     581         [ -  + ]:        797 :     if (rc != SQLITE_OK) {
     582 [ #  # ][ #  # ]:          0 :         isc_throw(SQLite3Error, "Could not bind " << class_ <<
         [ #  # ][ #  # ]
     583                 :            :                   " to SQL statement (zone)");
     584                 :            :     }
     585                 :            : 
     586                 :            :     // Get the data there and see if it found anything
     587                 :        797 :     rc = sqlite3_step(stmt);
     588         [ +  + ]:        797 :     if (rc == SQLITE_ROW) {
     589                 :        513 :         const int zone_id = sqlite3_column_int(stmt, 0);
     590                 :        513 :         sqlite3_reset(stmt);
     591                 :        513 :         return (pair<bool, int>(true, zone_id));
     592         [ +  - ]:        284 :     } else if (rc == SQLITE_DONE) {
     593                 :            :         // Free resources
     594                 :        284 :         sqlite3_reset(stmt);
     595                 :        284 :         return (pair<bool, int>(false, 0));
     596                 :            :     }
     597                 :            : 
     598                 :          0 :     sqlite3_reset(stmt);
     599 [ #  # ][ #  # ]:        797 :     isc_throw(DataSourceError, "Unexpected failure in sqlite3_step: " <<
         [ #  # ][ #  # ]
     600                 :            :               sqlite3_errmsg(dbparameters_->db_));
     601                 :            :     // Compilers might not realize isc_throw always throws
     602                 :            :     return (std::pair<bool, int>(false, 0));
     603                 :            : }
     604                 :            : 
     605                 :            : namespace {
     606                 :            : 
     607                 :            : // Conversion to plain char
     608                 :            : const char*
     609                 :      24057 : convertToPlainChar(const unsigned char* ucp, sqlite3 *db) {
     610         [ +  + ]:      24057 :     if (ucp == NULL) {
     611                 :            :         // The field can really be NULL, in which case we return an
     612                 :            :         // empty string, or sqlite may have run out of memory, in
     613                 :            :         // which case we raise an error
     614         [ -  + ]:       4849 :         if (sqlite3_errcode(db) == SQLITE_NOMEM) {
     615 [ #  # ][ #  # ]:      24057 :             isc_throw(DataSourceError,
     616                 :            :                       "Sqlite3 backend encountered a memory allocation "
     617                 :            :                       "error in sqlite3_column_text()");
     618                 :            :         } else {
     619                 :            :             return ("");
     620                 :            :         }
     621                 :            :     }
     622                 :            :     const void* p = ucp;
     623                 :            :     return (static_cast<const char*>(p));
     624                 :            : }
     625                 :            : 
     626                 :            : }
     627                 :            : class SQLite3Accessor::Context : public DatabaseAccessor::IteratorContext {
     628                 :            : public:
     629                 :            :     // Construct an iterator for all records. When constructed this
     630                 :            :     // way, the getNext() call will copy all fields
     631                 :            :     Context(const boost::shared_ptr<const SQLite3Accessor>& accessor, int id) :
     632                 :            :         iterator_type_(ITT_ALL),
     633                 :            :         accessor_(accessor),
     634                 :            :         statement_(NULL),
     635         [ +  - ]:         24 :         name_("")
     636                 :            :     {
     637                 :            :         // We create the statement now and then just keep getting data from it
     638                 :         24 :         statement_ = prepare(accessor->dbparameters_->db_,
     639         [ +  - ]:         24 :                              text_statements[ITERATE]);
     640         [ -  + ]:         24 :         bindZoneId(id);
     641                 :            :     }
     642                 :            : 
     643                 :            :     // What kind of query it is - selection of the statement for DB
     644                 :            :     enum QueryType {
     645                 :            :         QT_ANY, // Directly for a domain
     646                 :            :         QT_SUBDOMAINS, // Subdomains of a given domain
     647                 :            :         QT_NSEC3 // Domain in the NSEC3 namespace (the name is is the hash,
     648                 :            :                  // not the whole name)
     649                 :            :     };
     650                 :            : 
     651                 :            :     // Construct an iterator for records with a specific name. When constructed
     652                 :            :     // this way, the getNext() call will copy all fields except name
     653                 :       1846 :     Context(const boost::shared_ptr<const SQLite3Accessor>& accessor, int id,
     654                 :            :             const std::string& name, QueryType qtype) :
     655                 :            :         iterator_type_(qtype == QT_NSEC3 ? ITT_NSEC3 : ITT_NAME),
     656                 :            :         accessor_(accessor),
     657                 :            :         statement_(NULL),
     658 [ +  + ][ +  - ]:       3692 :         name_(name)
     659                 :            :     {
     660                 :            :         // Choose the statement text depending on the query type
     661                 :       1846 :         const char* statement(NULL);
     662   [ +  +  -  + ]:       1846 :         switch (qtype) {
     663                 :            :             case QT_ANY:
     664                 :            :                 statement = text_statements[ANY];
     665                 :            :                 break;
     666                 :            :             case QT_SUBDOMAINS:
     667                 :        309 :                 statement = text_statements[ANY_SUB];
     668                 :        309 :                 break;
     669                 :            :             case QT_NSEC3:
     670                 :         19 :                 statement = text_statements[NSEC3];
     671                 :         19 :                 break;
     672                 :            :             default:
     673                 :            :                 // Can Not Happen - there isn't any other type of query
     674                 :            :                 // and all the calls to the constructor are from this
     675                 :            :                 // file. Therefore no way to test it throws :-(.
     676 [ #  # ][ #  # ]:          0 :                 isc_throw(Unexpected,
     677                 :            :                           "Invalid qtype passed - unreachable code branch "
     678                 :            :                           "reached");
     679                 :            :         }
     680                 :            : 
     681                 :            :         // We create the statement now and then just keep getting data from it
     682         [ +  - ]:       1846 :         statement_ = prepare(accessor->dbparameters_->db_, statement);
     683         [ +  - ]:       1846 :         bindZoneId(id);
     684         [ +  - ]:       1846 :         bindName(name_);
     685                 :       1846 :     }
     686                 :            : 
     687                 :       7084 :     bool getNext(std::string (&data)[COLUMN_COUNT]) {
     688                 :            :         // If there's another row, get it
     689                 :            :         // If finalize has been called (e.g. when previous getNext() got
     690                 :            :         // SQLITE_DONE), directly return false
     691         [ +  + ]:       7084 :         if (statement_ == NULL) {
     692                 :            :             return false;
     693                 :            :         }
     694                 :       7080 :         const int rc(sqlite3_step(statement_));
     695         [ +  + ]:       7080 :         if (rc == SQLITE_ROW) {
     696                 :            :             // For both types, we copy the first four columns
     697                 :       5262 :             copyColumn(data, TYPE_COLUMN);
     698                 :       5262 :             copyColumn(data, TTL_COLUMN);
     699                 :            :             // The NSEC3 lookup does not provide the SIGTYPE, it is not
     700                 :            :             // necessary and not contained in the table.
     701         [ +  + ]:       5262 :             if (iterator_type_ != ITT_NSEC3) {
     702                 :       5249 :                 copyColumn(data, SIGTYPE_COLUMN);
     703                 :            :             }
     704                 :       5262 :             copyColumn(data, RDATA_COLUMN);
     705                 :            :             // Only copy Name if we are iterating over every record
     706         [ +  + ]:       5262 :             if (iterator_type_ == ITT_ALL) {
     707                 :        414 :                 copyColumn(data, NAME_COLUMN);
     708                 :            :             }
     709                 :            :             return (true);
     710         [ -  + ]:       1818 :         } else if (rc != SQLITE_DONE) {
     711 [ #  # ][ #  # ]:          0 :             isc_throw(DataSourceError,
         [ #  # ][ #  # ]
     712                 :            :                       "Unexpected failure in sqlite3_step: " <<
     713                 :            :                       sqlite3_errmsg(accessor_->dbparameters_->db_));
     714                 :            :         }
     715                 :            :         finalize();
     716                 :       7084 :         return (false);
     717                 :            :     }
     718                 :            : 
     719                 :       1870 :     virtual ~Context() {
     720                 :            :         finalize();
     721                 :       3740 :     }
     722                 :            : 
     723                 :            : private:
     724                 :            :     // Depending on which constructor is called, behaviour is slightly
     725                 :            :     // different. We keep track of what to do with the iterator type
     726                 :            :     // See description of getNext() and the constructors
     727                 :            :     enum IteratorType {
     728                 :            :         ITT_ALL,
     729                 :            :         ITT_NAME,
     730                 :            :         ITT_NSEC3
     731                 :            :     };
     732                 :            : 
     733                 :      21449 :     void copyColumn(std::string (&data)[COLUMN_COUNT], int column) {
     734                 :            :         data[column] = convertToPlainChar(sqlite3_column_text(statement_,
     735                 :            :                                                               column),
     736                 :      21449 :                                           accessor_->dbparameters_->db_);
     737                 :      21449 :     }
     738                 :            : 
     739                 :       1870 :     void bindZoneId(const int zone_id) {
     740         [ -  + ]:       1870 :         if (sqlite3_bind_int(statement_, 1, zone_id) != SQLITE_OK) {
     741                 :            :             finalize();
     742 [ #  # ][ #  # ]:          0 :             isc_throw(SQLite3Error, "Could not bind int " << zone_id <<
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     743                 :            :                       " to SQL statement: " <<
     744                 :            :                       sqlite3_errmsg(accessor_->dbparameters_->db_));
     745                 :            :         }
     746                 :       1870 :     }
     747                 :            : 
     748                 :       1846 :     void bindName(const std::string& name) {
     749         [ -  + ]:       1846 :         if (sqlite3_bind_text(statement_, 2, name.c_str(), -1,
     750                 :       1846 :                               SQLITE_TRANSIENT) != SQLITE_OK) {
     751                 :          0 :             const char* errmsg = sqlite3_errmsg(accessor_->dbparameters_->db_);
     752                 :            :             finalize();
     753 [ #  # ][ #  # ]:          0 :             isc_throw(SQLite3Error, "Could not bind text '" << name <<
         [ #  # ][ #  # ]
                 [ #  # ]
     754                 :            :                       "' to SQL statement: " << errmsg);
     755                 :            :         }
     756                 :       1846 :     }
     757                 :            : 
     758                 :          0 :     void finalize() {
     759         [ +  - ]:       3688 :         sqlite3_finalize(statement_);
     760                 :       3688 :         statement_ = NULL;
     761                 :          0 :     }
     762                 :            : 
     763                 :            :     const IteratorType iterator_type_;
     764                 :            :     boost::shared_ptr<const SQLite3Accessor> accessor_;
     765                 :            :     sqlite3_stmt* statement_;
     766                 :            :     const std::string name_;
     767                 :            : };
     768                 :            : 
     769                 :            : 
     770                 :            : // Methods to retrieve the various iterators
     771                 :            : 
     772                 :            : DatabaseAccessor::IteratorContextPtr
     773                 :       1827 : SQLite3Accessor::getRecords(const std::string& name, int id,
     774                 :            :                             bool subdomains) const
     775                 :            : {
     776                 :            :     return (IteratorContextPtr(new Context(shared_from_this(), id, name,
     777                 :            :                                            subdomains ?
     778                 :            :                                            Context::QT_SUBDOMAINS :
     779 [ +  - ][ +  + ]:       3654 :                                            Context::QT_ANY)));
         [ +  - ][ +  - ]
     780                 :            : }
     781                 :            : 
     782                 :            : DatabaseAccessor::IteratorContextPtr
     783                 :         19 : SQLite3Accessor::getNSEC3Records(const std::string& hash, int id) const {
     784                 :            :     return (IteratorContextPtr(new Context(shared_from_this(), id, hash,
     785 [ +  - ][ +  - ]:         38 :                                            Context::QT_NSEC3)));
                 [ +  - ]
     786                 :            : }
     787                 :            : 
     788                 :            : DatabaseAccessor::IteratorContextPtr
     789                 :         24 : SQLite3Accessor::getAllRecords(int id) const {
     790 [ +  - ][ +  - ]:         72 :     return (IteratorContextPtr(new Context(shared_from_this(), id)));
     791                 :            : }
     792                 :            : 
     793                 :            : 
     794                 :            : /// \brief Difference Iterator
     795                 :            : ///
     796                 :            : /// This iterator is used to search through the differences table for the
     797                 :            : /// resouce records making up an IXFR between two versions of a zone.
     798                 :            : 
     799                 :            : class SQLite3Accessor::DiffContext : public DatabaseAccessor::IteratorContext {
     800                 :            : public:
     801                 :            : 
     802                 :            :     /// \brief Constructor
     803                 :            :     ///
     804                 :            :     /// Constructs the iterator for the difference sequence.  It is
     805                 :            :     /// passed two parameters, the first and last versions in the difference
     806                 :            :     /// sequence.  Note that because of serial number rollover, it may well
     807                 :            :     /// be that the start serial number is greater than the end one.
     808                 :            :     ///
     809                 :            :     /// \param zone_id ID of the zone (in the zone table)
     810                 :            :     /// \param start Serial number of first version in difference sequence
     811                 :            :     /// \param end Serial number of last version in difference sequence
     812                 :            :     ///
     813                 :            :     /// \exception any A number of exceptions can be expected
     814                 :         26 :     DiffContext(const boost::shared_ptr<const SQLite3Accessor>& accessor,
     815                 :            :                 int zone_id, uint32_t start, uint32_t end) :
     816                 :            :         accessor_(accessor),
     817                 :         86 :         last_status_(SQLITE_ROW)
     818                 :            :     {
     819                 :            :         try {
     820         [ +  + ]:         26 :             int low_id = findIndex(LOW_DIFF_ID, zone_id, start, DIFF_DELETE);
     821         [ +  + ]:         19 :             int high_id = findIndex(HIGH_DIFF_ID, zone_id, end, DIFF_ADD);
     822                 :            : 
     823                 :            :             // Prepare the statement that will return data values
     824         [ +  - ]:         18 :             reset(DIFF_RECS);
     825         [ +  - ]:         18 :             bindInt(DIFF_RECS, 1, zone_id);
     826         [ +  - ]:         18 :             bindInt(DIFF_RECS, 2, low_id);
     827         [ +  - ]:         18 :             bindInt(DIFF_RECS, 3, high_id);
     828                 :            : 
     829                 :         16 :         } catch (...) {
     830                 :            :             // Something wrong, clear up everything.
     831         [ -  + ]:          8 :             accessor_->dbparameters_->finalizeStatements();
     832                 :          8 :             throw;
     833                 :            :         }
     834                 :         18 :     }
     835                 :            : 
     836                 :            :     /// \brief Destructor
     837                 :         36 :     virtual ~DiffContext()
     838                 :         36 :     {}
     839                 :            : 
     840                 :            :     /// \brief Get Next Diff Record
     841                 :            :     ///
     842                 :            :     /// Returns the next difference record in the difference sequence.
     843                 :            :     ///
     844                 :            :     /// \param data Array of std::strings COLUMN_COUNT long.  The results
     845                 :            :     ///        are returned in this.
     846                 :            :     ///
     847                 :            :     /// \return bool true if data is returned, false if not.
     848                 :            :     ///
     849                 :            :     /// \exception any Varied
     850                 :        665 :     bool getNext(std::string (&data)[COLUMN_COUNT]) {
     851                 :            : 
     852         [ +  + ]:        665 :         if (last_status_ != SQLITE_DONE) {
     853                 :            :             // Last call (if any) didn't reach end of result set, so we
     854                 :            :             // can read another row from it.
     855                 :            :             //
     856                 :            :             // Get a pointer to the statement for brevity (this does not
     857                 :            :             // transfer ownership of the statement to this class, so there is
     858                 :            :             // no need to tidy up after we have finished using it).
     859                 :            :             sqlite3_stmt* stmt =
     860                 :        661 :                 accessor_->dbparameters_->getStatement(DIFF_RECS);
     861                 :            : 
     862                 :        661 :             const int rc(sqlite3_step(stmt));
     863         [ +  + ]:        661 :             if (rc == SQLITE_ROW) {
     864                 :            :                 // Copy the data across to the output array
     865                 :        644 :                 copyColumn(DIFF_RECS, data, TYPE_COLUMN);
     866                 :        644 :                 copyColumn(DIFF_RECS, data, TTL_COLUMN);
     867                 :        644 :                 copyColumn(DIFF_RECS, data, NAME_COLUMN);
     868                 :        644 :                 copyColumn(DIFF_RECS, data, RDATA_COLUMN);
     869                 :            : 
     870         [ -  + ]:         17 :             } else if (rc != SQLITE_DONE) {
     871 [ #  # ][ #  # ]:          0 :                 isc_throw(DataSourceError,
         [ #  # ][ #  # ]
     872                 :            :                           "Unexpected failure in sqlite3_step: " <<
     873                 :            :                           sqlite3_errmsg(accessor_->dbparameters_->db_));
     874                 :            :             }
     875                 :        661 :             last_status_ = rc;
     876                 :            :         }
     877                 :        665 :         return (last_status_ == SQLITE_ROW);
     878                 :            :     }
     879                 :            : 
     880                 :            : private:
     881                 :            : 
     882                 :            :     /// \brief Reset prepared statement
     883                 :            :     ///
     884                 :            :     /// Sets up the statement so that new parameters can be attached to it and
     885                 :            :     /// that it can be used to query for another difference sequence.
     886                 :            :     ///
     887                 :            :     /// \param stindex Index of prepared statement to which to bind
     888                 :         63 :     void reset(int stindex) {
     889                 :         63 :         sqlite3_stmt* stmt = accessor_->dbparameters_->getStatement(stindex);
     890   [ +  -  -  + ]:        126 :         if ((sqlite3_reset(stmt) != SQLITE_OK) ||
                 [ -  + ]
     891                 :         63 :             (sqlite3_clear_bindings(stmt) != SQLITE_OK)) {
     892 [ #  # ][ #  # ]:          0 :             isc_throw(SQLite3Error, "Could not clear statement bindings in '" <<
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     893                 :            :                       text_statements[stindex] << "': " <<
     894                 :            :                       sqlite3_errmsg(accessor_->dbparameters_->db_));
     895                 :            :         }
     896                 :         63 :     }
     897                 :            : 
     898                 :            :     /// \brief Bind Int
     899                 :            :     ///
     900                 :            :     /// Binds an integer to a specific variable in a prepared statement.
     901                 :            :     ///
     902                 :            :     /// \param stindex Index of prepared statement to which to bind
     903                 :            :     /// \param varindex Index of variable to which to bind
     904                 :            :     /// \param value Value of variable to bind
     905                 :            :     /// \exception SQLite3Error on an error
     906                 :        189 :     void bindInt(int stindex, int varindex, sqlite3_int64 value) {
     907         [ -  + ]:        378 :         if (sqlite3_bind_int64(accessor_->dbparameters_->getStatement(stindex),
     908                 :        189 :                              varindex, value) != SQLITE_OK) {
     909 [ #  # ][ #  # ]:          0 :             isc_throw(SQLite3Error, "Could not bind value to parameter " <<
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     910                 :            :                       varindex << " in statement '" <<
     911                 :            :                       text_statements[stindex] << "': " <<
     912                 :            :                       sqlite3_errmsg(accessor_->dbparameters_->db_));
     913                 :            :         }
     914                 :        189 :     }
     915                 :            : 
     916                 :            :     ///\brief Get Single Value
     917                 :            :     ///
     918                 :            :     /// Executes a prepared statement (which has parameters bound to it)
     919                 :            :     /// for which the result of a single value is expected.
     920                 :            :     ///
     921                 :            :     /// \param stindex Index of prepared statement in statement table.
     922                 :            :     ///
     923                 :            :     /// \return Value of SELECT.
     924                 :            :     ///
     925                 :            :     /// \exception TooMuchData Multiple rows returned when one expected
     926                 :            :     /// \exception TooLittleData Zero rows returned when one expected
     927                 :            :     /// \exception DataSourceError SQLite3-related error
     928                 :         45 :     int getSingleValue(StatementID stindex) {
     929                 :            : 
     930                 :            :         // Get a pointer to the statement for brevity (does not transfer
     931                 :            :         // resources)
     932                 :         45 :         sqlite3_stmt* stmt = accessor_->dbparameters_->getStatement(stindex);
     933                 :            : 
     934                 :            :         // Execute the data.  Should be just one result
     935                 :         45 :         int rc = sqlite3_step(stmt);
     936                 :         45 :         int result = -1;
     937         [ +  + ]:         45 :         if (rc == SQLITE_ROW) {
     938                 :            : 
     939                 :            :             // Got some data, extract the value
     940                 :         37 :             result = sqlite3_column_int(stmt, 0);
     941                 :         37 :             rc = sqlite3_step(stmt);
     942         [ +  - ]:         37 :             if (rc == SQLITE_DONE) {
     943                 :            : 
     944                 :            :                 // All OK, exit with the value.
     945                 :            :                 return (result);
     946                 :            : 
     947         [ #  # ]:          0 :             } else if (rc == SQLITE_ROW) {
     948         [ #  # ]:          0 :                 isc_throw(TooMuchData, "request to return one value from "
     949                 :            :                           "diffs table returned multiple values");
     950                 :            :             }
     951         [ +  - ]:          8 :         } else if (rc == SQLITE_DONE) {
     952                 :            : 
     953                 :            :             // No data in the table.  A bare exception with no explanation is
     954                 :            :             // thrown, as it will be replaced by a more informative one by
     955                 :            :             // the caller.
     956         [ +  - ]:         16 :             isc_throw(TooLittleData, "");
     957                 :            :         }
     958                 :            : 
     959                 :            :         // We get here on an error.
     960 [ #  # ][ #  # ]:          0 :         isc_throw(DataSourceError, "could not get data from diffs table: " <<
         [ #  # ][ #  # ]
     961                 :            :                   sqlite3_errmsg(accessor_->dbparameters_->db_));
     962                 :            : 
     963                 :            :         // Keep the compiler happy with a return value.
     964                 :            :         return (result);
     965                 :            :     }
     966                 :            : 
     967                 :            :     /// \brief Find index
     968                 :            :     ///
     969                 :            :     /// Executes the prepared statement locating the high or low index in
     970                 :            :     /// the diffs table and returns that index.
     971                 :            :     ///
     972                 :            :     /// \param stmt_id Index of the prepared statement to execute
     973                 :            :     /// \param zone_id ID of the zone for which the index is being sought
     974                 :            :     /// \param serial Zone serial number for which an index is being sought.
     975                 :            :     /// \param diff Code to delete record additions or deletions
     976                 :            :     ///
     977                 :            :     /// \return int ID of the row in the difss table corresponding to the
     978                 :            :     ///         statement.
     979                 :            :     ///
     980                 :            :     /// \exception TooLittleData Internal error, no result returned when one
     981                 :            :     ///            was expected.
     982                 :            :     /// \exception NoSuchSerial Serial number not found.
     983                 :            :     /// \exception NoDiffsData No data for this zone found in diffs table
     984                 :         45 :     int findIndex(StatementID stindex, int zone_id, uint32_t serial, int diff) {
     985                 :            : 
     986                 :            :         // Set up the statement
     987                 :         45 :         reset(stindex);
     988                 :         45 :         bindInt(stindex, 1, zone_id);
     989                 :         45 :         bindInt(stindex, 2, serial);
     990                 :         45 :         bindInt(stindex, 3, diff);
     991                 :            : 
     992                 :            :         // Execute the statement
     993                 :         45 :         int result = -1;
     994                 :            :         try {
     995         [ +  + ]:         45 :             result = getSingleValue(stindex);
     996                 :            : 
     997         [ -  + ]:         16 :         } catch (const TooLittleData&) {
     998                 :            : 
     999                 :            :             // No data returned but the SQL query succeeded.  Only possibility
    1000                 :            :             // is that there is no entry in the differences table for the given
    1001                 :            :             // zone and version.
    1002 [ -  + ][ -  + ]:         24 :             isc_throw(NoSuchSerial, "No entry in differences table for" <<
         [ -  + ][ -  + ]
                 [ -  + ]
    1003                 :            :                       " zone ID " << zone_id << ", serial number " << serial);
    1004                 :            :         }
    1005                 :            : 
    1006                 :         37 :         return (result);
    1007                 :            :     }
    1008                 :            : 
    1009                 :            :     /// \brief Copy Column to Output
    1010                 :            :     ///
    1011                 :            :     /// Copies the textual data in the result set to the specified column
    1012                 :            :     /// in the output.
    1013                 :            :     ///
    1014                 :            :     /// \param stindex Index of prepared statement used to access data
    1015                 :            :     /// \param data Array of columns passed to getNext
    1016                 :            :     /// \param column Column of output to copy
    1017                 :       2576 :     void copyColumn(StatementID stindex, std::string (&data)[COLUMN_COUNT],
    1018                 :            :                     int column) {
    1019                 :            : 
    1020                 :            :         // Get a pointer to the statement for brevity (does not transfer
    1021                 :            :         // resources)
    1022                 :       2576 :         sqlite3_stmt* stmt = accessor_->dbparameters_->getStatement(stindex);
    1023                 :            :         data[column] = convertToPlainChar(sqlite3_column_text(stmt,
    1024                 :            :                                                               column),
    1025                 :       2576 :                                           accessor_->dbparameters_->db_);
    1026                 :       2576 :     }
    1027                 :            : 
    1028                 :            :     // Attributes
    1029                 :            : 
    1030                 :            :     boost::shared_ptr<const SQLite3Accessor> accessor_; // Accessor object
    1031                 :            :     int last_status_;           // Last status received from sqlite3_step
    1032                 :            : };
    1033                 :            : 
    1034                 :            : // ... and return the iterator
    1035                 :            : 
    1036                 :            : DatabaseAccessor::IteratorContextPtr
    1037                 :         26 : SQLite3Accessor::getDiffs(int id, uint32_t start, uint32_t end) const {
    1038                 :            :     return (IteratorContextPtr(new DiffContext(shared_from_this(), id, start,
    1039 [ +  - ][ +  + ]:         44 :                                end)));
    1040                 :            : }
    1041                 :            : 
    1042                 :            : 
    1043                 :            : 
    1044                 :            : pair<bool, int>
    1045                 :        196 : SQLite3Accessor::startUpdateZone(const string& zone_name, const bool replace) {
    1046         [ +  + ]:        196 :     if (dbparameters_->updating_zone) {
    1047 [ +  - ][ +  - ]:          2 :         isc_throw(DataSourceError,
    1048                 :            :                   "duplicate zone update on SQLite3 data source");
    1049                 :            :     }
    1050         [ +  + ]:        195 :     if (dbparameters_->in_transaction) {
    1051 [ +  - ][ +  - ]:          2 :         isc_throw(DataSourceError,
    1052                 :            :                   "zone update attempt in another SQLite3 transaction");
    1053                 :            :     }
    1054                 :            : 
    1055                 :        194 :     const pair<bool, int> zone_info(getZone(zone_name));
    1056         [ +  + ]:        194 :     if (!zone_info.first) {
    1057                 :          1 :         return (zone_info);
    1058                 :            :     }
    1059                 :            : 
    1060                 :        193 :     StatementProcessor(*dbparameters_, BEGIN,
    1061         [ +  - ]:        193 :                        "start an SQLite3 update transaction").exec();
    1062                 :            : 
    1063         [ +  + ]:        193 :     if (replace) {
    1064                 :            :         // First, clear all current data from tables.
    1065                 :            :         typedef pair<StatementID, const char* const> StatementSpec;
    1066                 :            :         const StatementSpec delzone_stmts[] =
    1067                 :            :             { StatementSpec(DEL_ZONE_RECORDS, "delete zone records"),
    1068                 :            :               StatementSpec(DEL_ZONE_NSEC3_RECORDS,
    1069                 :            :                             "delete zone NSEC3 records") };
    1070                 :            :         try {
    1071         [ +  + ]:        346 :             for (size_t i = 0;
    1072                 :            :                  i < sizeof(delzone_stmts) / sizeof(delzone_stmts[0]);
    1073                 :            :                  ++i) {
    1074                 :        231 :                 StatementProcessor delzone_proc(*dbparameters_,
    1075                 :            :                                                 delzone_stmts[i].first,
    1076 [ +  - ][ +  - ]:        462 :                                                 delzone_stmts[i].second);
    1077         [ +  - ]:        231 :                 delzone_proc.bindInt(1, zone_info.second);
    1078         [ +  + ]:        231 :                 delzone_proc.exec();
    1079                 :            :             }
    1080         [ -  + ]:          2 :         } catch (const DataSourceError&) {
    1081                 :            :             // Once we start a transaction, if something unexpected happens
    1082                 :            :             // we need to rollback the transaction so that a subsequent update
    1083                 :            :             // is still possible with this accessor.
    1084                 :          1 :             StatementProcessor(*dbparameters_, ROLLBACK,
    1085 [ -  + ][ -  + ]:          1 :                                "rollback an SQLite3 transaction").exec();
                 [ -  + ]
    1086                 :          1 :             throw;
    1087                 :            :         }
    1088                 :            :     }
    1089                 :            : 
    1090                 :        192 :     dbparameters_->in_transaction = true;
    1091                 :        192 :     dbparameters_->updating_zone = true;
    1092                 :        192 :     dbparameters_->updated_zone_id = zone_info.second;
    1093                 :        192 :     dbparameters_->updated_zone_origin_ = zone_name;
    1094                 :            : 
    1095                 :        193 :     return (zone_info);
    1096                 :            : }
    1097                 :            : 
    1098                 :            : void
    1099                 :         30 : SQLite3Accessor::startTransaction() {
    1100         [ +  + ]:         30 :     if (dbparameters_->in_transaction) {
    1101 [ +  - ][ +  - ]:          4 :         isc_throw(DataSourceError,
    1102                 :            :                   "duplicate transaction on SQLite3 data source");
    1103                 :            :     }
    1104                 :            : 
    1105                 :         28 :     StatementProcessor(*dbparameters_, BEGIN,
    1106         [ +  - ]:         28 :                        "start an SQLite3 transaction").exec();
    1107                 :         28 :     dbparameters_->in_transaction = true;
    1108                 :         28 : }
    1109                 :            : 
    1110                 :            : void
    1111                 :        167 : SQLite3Accessor::commit() {
    1112         [ +  + ]:        167 :     if (!dbparameters_->in_transaction) {
    1113 [ +  - ][ +  - ]:          2 :         isc_throw(DataSourceError, "performing commit on SQLite3 "
    1114                 :            :                   "data source without transaction");
    1115                 :            :     }
    1116                 :            : 
    1117                 :        166 :     StatementProcessor(*dbparameters_, COMMIT,
    1118         [ +  + ]:        166 :                        "commit an SQLite3 transaction").exec();
    1119                 :        163 :     dbparameters_->in_transaction = false;
    1120                 :        163 :     dbparameters_->updating_zone = false;
    1121                 :        163 :     dbparameters_->updated_zone_id = -1;
    1122                 :        163 :     dbparameters_->updated_zone_origin_.clear();
    1123                 :        163 : }
    1124                 :            : 
    1125                 :            : void
    1126                 :         47 : SQLite3Accessor::rollback() {
    1127         [ +  + ]:         47 :     if (!dbparameters_->in_transaction) {
    1128 [ +  - ][ +  - ]:          2 :         isc_throw(DataSourceError, "performing rollback on SQLite3 "
    1129                 :            :                   "data source without transaction");
    1130                 :            :     }
    1131                 :            : 
    1132                 :         46 :     StatementProcessor(*dbparameters_, ROLLBACK,
    1133         [ +  + ]:         46 :                        "rollback an SQLite3 transaction").exec();
    1134                 :         45 :     dbparameters_->in_transaction = false;
    1135                 :         45 :     dbparameters_->updating_zone = false;
    1136                 :         45 :     dbparameters_->updated_zone_id = -1;
    1137                 :         45 :     dbparameters_->updated_zone_origin_.clear();
    1138                 :         45 : }
    1139                 :            : 
    1140                 :            : namespace {
    1141                 :            : // Commonly used code sequence for adding/deleting record
    1142                 :            : template <typename COLUMNS_TYPE>
    1143                 :            : void
    1144                 :        440 : doUpdate(SQLite3Parameters& dbparams, StatementID stmt_id,
    1145                 :            :          COLUMNS_TYPE update_params, const char* exec_desc)
    1146                 :            : {
    1147 [ +  - ][ +  - ]:      14832 :     StatementProcessor proc(dbparams, stmt_id, exec_desc);
    1148                 :            : 
    1149                 :       7416 :     int param_id = 0;
    1150 [ +  - ][ +  - ]:       7416 :     proc.bindInt(++param_id, dbparams.updated_zone_id);
                 [ +  - ]
    1151                 :            :     const size_t column_count =
    1152                 :            :         sizeof(update_params) / sizeof(update_params[0]);
    1153 [ +  + ][ +  + ]:      50581 :     for (int i = 0; i < column_count; ++i) {
                 [ +  + ]
    1154                 :            :         // The old sqlite3 data source API assumes NULL for an empty column.
    1155                 :            :         // We need to provide compatibility at least for now.
    1156 [ +  - ][ +  - ]:      79520 :         proc.bindText(++param_id, update_params[i].empty() ? NULL :
         [ +  - ][ +  - ]
         [ +  + ][ +  - ]
    1157                 :            :                       update_params[i].c_str(), SQLITE_TRANSIENT);
    1158                 :            :     }
    1159 [ +  - ][ +  - ]:       7416 :     proc.exec();
                 [ +  - ]
    1160                 :        440 : }
    1161                 :            : }
    1162                 :            : 
    1163                 :            : void
    1164                 :       6966 : SQLite3Accessor::addRecordToZone(const string (&columns)[ADD_COLUMN_COUNT]) {
    1165         [ +  + ]:       6966 :     if (!dbparameters_->updating_zone) {
    1166 [ +  - ][ +  - ]:          2 :         isc_throw(DataSourceError, "adding record to SQLite3 "
    1167                 :            :                   "data source without transaction");
    1168                 :            :     }
    1169                 :            :     doUpdate<const string (&)[ADD_COLUMN_COUNT]>(
    1170                 :       6965 :         *dbparameters_, ADD_RECORD, columns, "add record to zone");
    1171                 :       6965 : }
    1172                 :            : 
    1173                 :            : void
    1174                 :         12 : SQLite3Accessor::addNSEC3RecordToZone(
    1175                 :            :     const string (&columns)[ADD_NSEC3_COLUMN_COUNT])
    1176                 :            : {
    1177         [ +  + ]:         12 :     if (!dbparameters_->updating_zone) {
    1178 [ +  - ][ +  - ]:          2 :         isc_throw(DataSourceError, "adding NSEC3-related record to SQLite3 "
    1179                 :            :                   "data source without transaction");
    1180                 :            :     }
    1181                 :            : 
    1182                 :            :     // XXX: the current implementation of SQLite3 schema requires the 'owner'
    1183                 :            :     // column, and the current implementation of getAllRecords() relies on it,
    1184                 :            :     // while the addNSEC3RecordToZone interface doesn't provide it explicitly.
    1185                 :            :     // We should revisit it at the design level, but for now we internally
    1186                 :            :     // convert the given parameter to satisfy the internal requirements.
    1187                 :            :     const string sqlite3_columns[ADD_NSEC3_COLUMN_COUNT + 1] =
    1188                 :            :         { columns[ADD_NSEC3_HASH],
    1189                 :         22 :           columns[ADD_NSEC3_HASH] + "." + dbparameters_->updated_zone_origin_,
    1190                 :            :           columns[ADD_NSEC3_TTL],
    1191         [ +  - ]:         88 :           columns[ADD_NSEC3_TYPE], columns[ADD_NSEC3_RDATA] };
           [ +  -  +  - ]
         [ +  - ][ +  - ]
                 [ #  # ]
    1192                 :            :     doUpdate<const string (&)[ADD_NSEC3_COLUMN_COUNT + 1]>(
    1193                 :         11 :         *dbparameters_, ADD_NSEC3_RECORD, sqlite3_columns,
    1194 [ +  + ][ #  # ]:         66 :         "add NSEC3 record to zone");
    1195                 :         11 : }
    1196                 :            : 
    1197                 :            : void
    1198                 :        437 : SQLite3Accessor::deleteRecordInZone(const string (&params)[DEL_PARAM_COUNT]) {
    1199         [ +  + ]:        437 :     if (!dbparameters_->updating_zone) {
    1200 [ +  - ][ +  - ]:          2 :         isc_throw(DataSourceError, "deleting record in SQLite3 "
    1201                 :            :                   "data source without transaction");
    1202                 :            :     }
    1203                 :            :     doUpdate<const string (&)[DEL_PARAM_COUNT]>(
    1204                 :        436 :         *dbparameters_, DEL_RECORD, params, "delete record from zone");
    1205                 :        436 : }
    1206                 :            : 
    1207                 :            : void
    1208                 :          5 : SQLite3Accessor::deleteNSEC3RecordInZone(
    1209                 :            :     const string (&params)[DEL_PARAM_COUNT])
    1210                 :            : {
    1211         [ +  + ]:          5 :     if (!dbparameters_->updating_zone) {
    1212 [ +  - ][ +  - ]:          2 :         isc_throw(DataSourceError, "deleting NSEC3-related record in SQLite3 "
    1213                 :            :                   "data source without transaction");
    1214                 :            :     }
    1215                 :            :     doUpdate<const string (&)[DEL_PARAM_COUNT]>(
    1216                 :          4 :         *dbparameters_, DEL_NSEC3_RECORD, params,
    1217                 :          4 :         "delete NSEC3 record from zone");
    1218                 :          4 : }
    1219                 :            : 
    1220                 :            : void
    1221                 :        839 : SQLite3Accessor::addRecordDiff(int zone_id, uint32_t serial,
    1222                 :            :                                DiffOperation operation,
    1223                 :            :                                const std::string (&params)[DIFF_PARAM_COUNT])
    1224                 :            : {
    1225         [ +  + ]:        839 :     if (!dbparameters_->updating_zone) {
    1226 [ +  - ][ +  - ]:          4 :         isc_throw(DataSourceError, "adding record diff without update "
         [ +  - ][ +  - ]
    1227                 :            :                   "transaction on " << getDBName());
    1228                 :            :     }
    1229         [ +  + ]:        837 :     if (zone_id != dbparameters_->updated_zone_id) {
    1230 [ +  - ][ +  - ]:          2 :         isc_throw(DataSourceError, "bad zone ID for adding record diff on "
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
    1231                 :            :                   << getDBName() << ": " << zone_id << ", must be "
    1232                 :            :                   << dbparameters_->updated_zone_id);
    1233                 :            :     }
    1234                 :            : 
    1235                 :        836 :     StatementProcessor proc(*dbparameters_, ADD_RECORD_DIFF,
    1236                 :       1672 :                             "add record diff");
    1237                 :        836 :     int param_id = 0;
    1238         [ +  - ]:        836 :     proc.bindInt(++param_id, zone_id);
    1239         [ +  - ]:        836 :     proc.bindInt64(++param_id, serial);
    1240         [ +  - ]:        836 :     proc.bindInt(++param_id, operation);
    1241         [ +  + ]:       4180 :     for (int i = 0; i < DIFF_PARAM_COUNT; ++i) {
    1242         [ +  - ]:       3344 :         proc.bindText(++param_id, params[i].c_str(), SQLITE_TRANSIENT);
    1243                 :            :     }
    1244         [ +  - ]:        836 :     proc.exec();
    1245                 :        836 : }
    1246                 :            : 
    1247                 :            : std::string
    1248                 :         32 : SQLite3Accessor::findPreviousName(int zone_id, const std::string& rname)
    1249                 :            :     const
    1250                 :            : {
    1251                 :         32 :     sqlite3_stmt* const stmt = dbparameters_->getStatement(FIND_PREVIOUS);
    1252                 :         32 :     sqlite3_reset(stmt);
    1253                 :         32 :     sqlite3_clear_bindings(stmt);
    1254                 :            : 
    1255         [ -  + ]:         32 :     if (sqlite3_bind_int(stmt, 1, zone_id) != SQLITE_OK) {
    1256 [ #  # ][ #  # ]:          0 :         isc_throw(SQLite3Error, "Could not bind zone ID " << zone_id <<
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
    1257                 :            :                   " to SQL statement (find previous): " <<
    1258                 :            :                   sqlite3_errmsg(dbparameters_->db_));
    1259                 :            :     }
    1260         [ -  + ]:         32 :     if (sqlite3_bind_text(stmt, 2, rname.c_str(), -1, SQLITE_STATIC) !=
    1261                 :            :         SQLITE_OK) {
    1262 [ #  # ][ #  # ]:          0 :         isc_throw(SQLite3Error, "Could not bind name " << rname <<
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
    1263                 :            :                   " to SQL statement (find previous): " <<
    1264                 :            :                   sqlite3_errmsg(dbparameters_->db_));
    1265                 :            :     }
    1266                 :            : 
    1267                 :          5 :     std::string result;
    1268         [ +  - ]:         32 :     const int rc = sqlite3_step(stmt);
    1269         [ +  + ]:         32 :     if (rc == SQLITE_ROW) {
    1270                 :            :         // We found it
    1271                 :            :         result = convertToPlainChar(sqlite3_column_text(stmt, 0),
    1272 [ +  - ][ +  - ]:         27 :                                     dbparameters_->db_);
    1273                 :            :     }
    1274         [ +  - ]:         32 :     sqlite3_reset(stmt);
    1275                 :            : 
    1276         [ +  + ]:         32 :     if (rc == SQLITE_DONE) {
    1277                 :            :         // No NSEC records here, this DB doesn't support DNSSEC or
    1278                 :            :         // we asked before the apex
    1279 [ +  - ][ +  - ]:         10 :         isc_throw(isc::NotImplemented, "The zone doesn't support DNSSEC or "
    1280                 :            :                   "query before apex");
    1281                 :            :     }
    1282                 :            : 
    1283         [ -  + ]:         27 :     if (rc != SQLITE_ROW && rc != SQLITE_DONE) {
    1284                 :            :         // Some kind of error
    1285 [ #  # ][ #  # ]:          0 :         isc_throw(SQLite3Error, "Could not get data for previous name");
                 [ #  # ]
    1286                 :            :     }
    1287                 :            : 
    1288                 :         27 :     return (result);
    1289                 :            : }
    1290                 :            : 
    1291                 :            : std::string
    1292                 :          6 : SQLite3Accessor::findPreviousNSEC3Hash(int zone_id, const std::string& hash)
    1293                 :            :     const
    1294                 :            : {
    1295                 :          6 :     sqlite3_stmt* const stmt = dbparameters_->getStatement(NSEC3_PREVIOUS);
    1296                 :          6 :     sqlite3_reset(stmt);
    1297                 :          6 :     sqlite3_clear_bindings(stmt);
    1298                 :            : 
    1299         [ -  + ]:          6 :     if (sqlite3_bind_int(stmt, 1, zone_id) != SQLITE_OK) {
    1300 [ #  # ][ #  # ]:          0 :         isc_throw(SQLite3Error, "Could not bind zone ID " << zone_id <<
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
    1301                 :            :                   " to SQL statement (find previous NSEC3): " <<
    1302                 :            :                   sqlite3_errmsg(dbparameters_->db_));
    1303                 :            :     }
    1304         [ -  + ]:          6 :     if (sqlite3_bind_text(stmt, 2, hash.c_str(), -1, SQLITE_STATIC) !=
    1305                 :            :         SQLITE_OK) {
    1306 [ #  # ][ #  # ]:          0 :         isc_throw(SQLite3Error, "Could not bind hash " << hash <<
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
    1307                 :            :                   " to SQL statement (find previous NSEC3): " <<
    1308                 :            :                   sqlite3_errmsg(dbparameters_->db_));
    1309                 :            :     }
    1310                 :            : 
    1311                 :          1 :     std::string result;
    1312         [ +  - ]:          6 :     const int rc = sqlite3_step(stmt);
    1313         [ +  + ]:          6 :     if (rc == SQLITE_ROW) {
    1314                 :            :         // We found it
    1315                 :            :         result = convertToPlainChar(sqlite3_column_text(stmt, 0),
    1316 [ +  - ][ +  - ]:          3 :                                     dbparameters_->db_);
    1317                 :            :     }
    1318         [ +  - ]:          6 :     sqlite3_reset(stmt);
    1319                 :            : 
    1320         [ -  + ]:          6 :     if (rc != SQLITE_ROW && rc != SQLITE_DONE) {
    1321                 :            :         // Some kind of error
    1322 [ #  # ][ #  # ]:          0 :         isc_throw(SQLite3Error, "Could not get data for previous hash");
                 [ #  # ]
    1323                 :            :     }
    1324                 :            : 
    1325         [ +  + ]:          6 :     if (rc == SQLITE_DONE) {
    1326                 :            :         // No NSEC3 records before this hash. This means we should wrap
    1327                 :            :         // around and take the last one.
    1328         [ +  - ]:          3 :         sqlite3_stmt* const stmt = dbparameters_->getStatement(NSEC3_LAST);
    1329         [ +  - ]:          3 :         sqlite3_reset(stmt);
    1330         [ +  - ]:          3 :         sqlite3_clear_bindings(stmt);
    1331                 :            : 
    1332 [ +  - ][ -  + ]:          3 :         if (sqlite3_bind_int(stmt, 1, zone_id) != SQLITE_OK) {
    1333 [ #  # ][ #  # ]:          0 :             isc_throw(SQLite3Error, "Could not bind zone ID " << zone_id <<
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1334                 :            :                       " to SQL statement (find last NSEC3): " <<
    1335                 :            :                       sqlite3_errmsg(dbparameters_->db_));
    1336                 :            :         }
    1337                 :            : 
    1338         [ +  - ]:          3 :         const int rc = sqlite3_step(stmt);
    1339         [ +  + ]:          3 :         if (rc == SQLITE_ROW) {
    1340                 :            :             // We found it
    1341                 :            :             result = convertToPlainChar(sqlite3_column_text(stmt, 0),
    1342 [ +  - ][ +  - ]:          2 :                                         dbparameters_->db_);
    1343                 :            :         }
    1344         [ +  - ]:          3 :         sqlite3_reset(stmt);
    1345                 :            : 
    1346         [ -  + ]:          3 :         if (rc != SQLITE_ROW && rc != SQLITE_DONE) {
    1347                 :            :             // Some kind of error
    1348 [ #  # ][ #  # ]:          0 :             isc_throw(SQLite3Error, "Could not get data for last hash");
                 [ #  # ]
    1349                 :            :         }
    1350                 :            : 
    1351         [ +  + ]:          3 :         if (rc == SQLITE_DONE) {
    1352                 :            :             // No NSEC3 at all in the zone. Well, bad luck, but you should not
    1353                 :            :             // have asked in the first place.
    1354 [ +  - ][ +  - ]:          2 :             isc_throw(DataSourceError, "No NSEC3 in this zone");
                 [ +  - ]
    1355                 :            :         }
    1356                 :            :     }
    1357                 :            : 
    1358                 :          5 :     return (result);
    1359                 :            : }
    1360                 :            : 
    1361                 :            : } // end of namespace datasrc
    1362                 :        541 : } // end of namespace isc

Generated by: LCOV version 1.9