Commit e2ada81c authored by JINMEI Tatuya's avatar JINMEI Tatuya
Browse files

[master] Merge branch 'trac1068review1'

with fixing conflicts:
	src/lib/datasrc/database.cc
	src/lib/datasrc/database.h
	src/lib/datasrc/sqlite3_accessor.cc
	src/lib/datasrc/tests/Makefile.am
	src/lib/datasrc/tests/sqlite3_accessor_unittest.cc
parents 30df4357 0953b3f5
......@@ -856,6 +856,7 @@ AC_CONFIG_FILES([Makefile
src/lib/exceptions/tests/Makefile
src/lib/datasrc/Makefile
src/lib/datasrc/tests/Makefile
src/lib/datasrc/tests/testdata/Makefile
src/lib/xfr/Makefile
src/lib/log/Makefile
src/lib/log/compiler/Makefile
......
......@@ -38,10 +38,10 @@ namespace isc {
namespace datasrc {
DatabaseClient::DatabaseClient(boost::shared_ptr<DatabaseAccessor>
database) :
database_(database)
accessor) :
accessor_(accessor)
{
if (database_.get() == NULL) {
if (!accessor_) {
isc_throw(isc::InvalidParameter,
"No database provided to DatabaseClient");
}
......@@ -49,21 +49,21 @@ DatabaseClient::DatabaseClient(boost::shared_ptr<DatabaseAccessor>
DataSourceClient::FindResult
DatabaseClient::findZone(const Name& name) const {
std::pair<bool, int> zone(database_->getZone(name.toText()));
std::pair<bool, int> zone(accessor_->getZone(name.toText()));
// Try exact first
if (zone.first) {
return (FindResult(result::SUCCESS,
ZoneFinderPtr(new Finder(database_,
ZoneFinderPtr(new Finder(accessor_,
zone.second, name))));
}
// Then super domains
// Start from 1, as 0 is covered above
for (size_t i(1); i < name.getLabelCount(); ++i) {
isc::dns::Name superdomain(name.split(i));
zone = database_->getZone(superdomain.toText());
zone = accessor_->getZone(superdomain.toText());
if (zone.first) {
return (FindResult(result::PARTIALMATCH,
ZoneFinderPtr(new Finder(database_,
ZoneFinderPtr(new Finder(accessor_,
zone.second,
superdomain))));
}
......@@ -72,10 +72,9 @@ DatabaseClient::findZone(const Name& name) const {
return (FindResult(result::NOTFOUND, ZoneFinderPtr()));
}
DatabaseClient::Finder::Finder(boost::shared_ptr<DatabaseAccessor>
database, int zone_id,
const isc::dns::Name& origin) :
database_(database),
DatabaseClient::Finder::Finder(boost::shared_ptr<DatabaseAccessor> accessor,
int zone_id, const isc::dns::Name& origin) :
accessor_(accessor),
zone_id_(zone_id),
origin_(origin)
{ }
......@@ -184,7 +183,7 @@ DatabaseClient::Finder::getRRset(const isc::dns::Name& name,
// Request the context
DatabaseAccessor::IteratorContextPtr
context(database_->getRecords(name.toText(), zone_id_));
context(accessor_->getRecords(name.toText(), zone_id_));
// It must not return NULL, that's a bug of the implementation
if (!context) {
isc_throw(isc::Unexpected, "Iterator context null at " +
......@@ -232,7 +231,7 @@ DatabaseClient::Finder::getRRset(const isc::dns::Name& name,
addOrCreate(result_rrset, *construct_name, getClass(),
cur_type, cur_ttl,
columns[DatabaseAccessor::RDATA_COLUMN],
*database_);
*accessor_);
} else if (type != NULL && cur_type == *type) {
if (result_rrset &&
result_rrset->getType() == isc::dns::RRType::CNAME()) {
......@@ -246,7 +245,7 @@ DatabaseClient::Finder::getRRset(const isc::dns::Name& name,
addOrCreate(result_rrset, *construct_name, getClass(),
cur_type, cur_ttl,
columns[DatabaseAccessor::RDATA_COLUMN],
*database_);
*accessor_);
} else if (want_cname && cur_type == isc::dns::RRType::CNAME()) {
// There should be no other data, so result_rrset should
// be empty.
......@@ -257,7 +256,7 @@ DatabaseClient::Finder::getRRset(const isc::dns::Name& name,
addOrCreate(result_rrset, *construct_name, getClass(),
cur_type, cur_ttl,
columns[DatabaseAccessor::RDATA_COLUMN],
*database_);
*accessor_);
} else if (want_dname && cur_type == isc::dns::RRType::DNAME()) {
// There should be max one RR of DNAME present
if (result_rrset &&
......@@ -268,7 +267,7 @@ DatabaseClient::Finder::getRRset(const isc::dns::Name& name,
addOrCreate(result_rrset, *construct_name, getClass(),
cur_type, cur_ttl,
columns[DatabaseAccessor::RDATA_COLUMN],
*database_);
*accessor_);
} else if (cur_type == isc::dns::RRType::RRSIG()) {
// If we get signatures before we get the actual data, we
// can't know which ones to keep and which to drop...
......@@ -304,7 +303,7 @@ bool
DatabaseClient::Finder::hasSubdomains(const std::string& name) {
// Request the context
DatabaseAccessor::IteratorContextPtr
context(database_->getRecords(name, zone_id_, true));
context(accessor_->getRecords(name, zone_id_, true));
// It must not return NULL, that's a bug of the implementation
if (!context) {
isc_throw(isc::Unexpected, "Iterator context null at " + name);
......@@ -328,7 +327,7 @@ DatabaseClient::Finder::find(const isc::dns::Name& name,
ZoneFinder::Result result_status = SUCCESS;
std::pair<bool, isc::dns::RRsetPtr> found;
logger.debug(DBG_TRACE_DETAILED, DATASRC_DATABASE_FIND_RECORDS)
.arg(database_->getDBName()).arg(name).arg(type);
.arg(accessor_->getDBName()).arg(name).arg(type);
// In case we are in GLUE_OK mode and start matching wildcards,
// we can't do it under NS, so we store it here to check
isc::dns::RRsetPtr first_ns;
......@@ -365,12 +364,12 @@ DatabaseClient::Finder::find(const isc::dns::Name& name,
if (result_rrset->getType() == isc::dns::RRType::NS()) {
LOG_DEBUG(logger, DBG_TRACE_DETAILED,
DATASRC_DATABASE_FOUND_DELEGATION).
arg(database_->getDBName()).arg(superdomain);
arg(accessor_->getDBName()).arg(superdomain);
result_status = DELEGATION;
} else {
LOG_DEBUG(logger, DBG_TRACE_DETAILED,
DATASRC_DATABASE_FOUND_DNAME).
arg(database_->getDBName()).arg(superdomain);
arg(accessor_->getDBName()).arg(superdomain);
result_status = DNAME;
}
// Don't search more
......@@ -389,7 +388,7 @@ DatabaseClient::Finder::find(const isc::dns::Name& name,
result_rrset->getType() == isc::dns::RRType::NS()) {
LOG_DEBUG(logger, DBG_TRACE_DETAILED,
DATASRC_DATABASE_FOUND_DELEGATION_EXACT).
arg(database_->getDBName()).arg(name);
arg(accessor_->getDBName()).arg(name);
result_status = DELEGATION;
} else if (result_rrset && type != isc::dns::RRType::CNAME() &&
result_rrset->getType() == isc::dns::RRType::CNAME()) {
......@@ -403,7 +402,7 @@ DatabaseClient::Finder::find(const isc::dns::Name& name,
if (hasSubdomains(name.toText())) {
LOG_DEBUG(logger, DBG_TRACE_DETAILED,
DATASRC_DATABASE_FOUND_EMPTY_NONTERMINAL).
arg(database_->getDBName()).arg(name);
arg(accessor_->getDBName()).arg(name);
records_found = true;
} else {
// It's not empty non-terminal. So check for wildcards.
......@@ -433,7 +432,7 @@ DatabaseClient::Finder::find(const isc::dns::Name& name,
glue_ok = false;
LOG_DEBUG(logger, DBG_TRACE_DETAILED,
DATASRC_DATABASE_WILDCARD_CANCEL_NS).
arg(database_->getDBName()).arg(wildcard).
arg(accessor_->getDBName()).arg(wildcard).
arg(first_ns->getName());
} else if (!hasSubdomains(name.split(i - 1).toText()))
{
......@@ -445,12 +444,12 @@ DatabaseClient::Finder::find(const isc::dns::Name& name,
result_rrset = found.second;
LOG_DEBUG(logger, DBG_TRACE_DETAILED,
DATASRC_DATABASE_WILDCARD).
arg(database_->getDBName()).arg(wildcard).
arg(accessor_->getDBName()).arg(wildcard).
arg(name);
} else {
LOG_DEBUG(logger, DBG_TRACE_DETAILED,
DATASRC_DATABASE_WILDCARD_CANCEL_SUB).
arg(database_->getDBName()).arg(wildcard).
arg(accessor_->getDBName()).arg(wildcard).
arg(name).arg(superdomain);
}
break;
......@@ -459,7 +458,7 @@ DatabaseClient::Finder::find(const isc::dns::Name& name,
records_found = true;
LOG_DEBUG(logger, DBG_TRACE_DETAILED,
DATASRC_DATABASE_WILDCARD_EMPTY).
arg(database_->getDBName()).arg(wildcard).
arg(accessor_->getDBName()).arg(wildcard).
arg(name);
break;
}
......@@ -472,20 +471,20 @@ DatabaseClient::Finder::find(const isc::dns::Name& name,
if (records_found) {
logger.debug(DBG_TRACE_DETAILED,
DATASRC_DATABASE_FOUND_NXRRSET)
.arg(database_->getDBName()).arg(name)
.arg(accessor_->getDBName()).arg(name)
.arg(getClass()).arg(type);
result_status = NXRRSET;
} else {
logger.debug(DBG_TRACE_DETAILED,
DATASRC_DATABASE_FOUND_NXDOMAIN)
.arg(database_->getDBName()).arg(name)
.arg(accessor_->getDBName()).arg(name)
.arg(getClass()).arg(type);
result_status = NXDOMAIN;
}
} else {
logger.debug(DBG_TRACE_DETAILED,
DATASRC_DATABASE_FOUND_RRSET)
.arg(database_->getDBName()).arg(*result_rrset);
.arg(accessor_->getDBName()).arg(*result_rrset);
}
return (FindResult(result_status, result_rrset));
}
......@@ -580,7 +579,7 @@ private:
ZoneIteratorPtr
DatabaseClient::getIterator(const isc::dns::Name& name) const {
// Get the zone
std::pair<bool, int> zone(database_->getZone(name.toText()));
std::pair<bool, int> zone(accessor_->getZone(name.toText()));
if (!zone.first) {
// No such zone, can't continue
isc_throw(DataSourceError, "Zone " + name.toText() +
......@@ -589,7 +588,7 @@ DatabaseClient::getIterator(const isc::dns::Name& name) const {
}
// Request the context
DatabaseAccessor::IteratorContextPtr
context(database_->getAllRecords(zone.second));
context(accessor_->getAllRecords(zone.second));
// It must not return NULL, that's a bug of the implementation
if (context == DatabaseAccessor::IteratorContextPtr()) {
isc_throw(isc::Unexpected, "Iterator context null at " +
......
......@@ -70,6 +70,38 @@ public:
///< the largest other element in this enum plus 1.
};
/**
* Definitions of the fields to be passed to addRecordToZone().
*
* Each derived implementation of addRecordToZone() should expect
* the "columns" vector to be filled with the values as described in this
* enumeration, in this order.
*/
enum AddRecordColumns {
ADD_NAME = 0, ///< The owner name of the record (a domain name)
ADD_REV_NAME = 1, ///< Reversed name of NAME (used for DNSSEC)
ADD_TTL = 2, ///< The TTL of the record (in numeric form)
ADD_TYPE = 3, ///< The RRType of the record (A/NS/TXT etc.)
ADD_SIGTYPE = 4, ///< For RRSIG records, this contains the RRTYPE
///< the RRSIG covers.
ADD_RDATA = 5, ///< Full text representation of the record's RDATA
ADD_COLUMN_COUNT = 6 ///< Number of columns
};
/**
* Definitions of the fields to be passed to deleteRecordInZone().
*
* Each derived implementation of deleteRecordInZone() should expect
* the "params" vector to be filled with the values as described in this
* enumeration, in this order.
*/
enum DeleteRecordParams {
DEL_NAME = 0, ///< The owner name of the record (a domain name)
DEL_TYPE = 1, ///< The RRType of the record (A/NS/TXT etc.)
DEL_RDATA = 2, ///< Full text representation of the record's RDATA
DEL_PARAM_COUNT = 3 ///< Number of parameters
};
/**
* \brief Destructor
*
......@@ -205,6 +237,189 @@ public:
*/
virtual IteratorContextPtr getAllRecords(int id) const = 0;
/// Start a transaction for updating a zone.
///
/// Each derived class version of this method starts a database
/// transaction to make updates to the given name of zone (whose class was
/// specified at the construction of the class).
///
/// If \c replace is true, any existing records of the zone will be
/// deleted on successful completion of updates (after
/// \c commitUpdateZone()); if it's false, the existing records will be
/// intact unless explicitly deleted by \c deleteRecordInZone().
///
/// A single \c DatabaseAccessor instance can perform at most one update
/// transaction; a duplicate call to this method before
/// \c commitUpdateZone() or \c rollbackUpdateZone() will result in
/// a \c DataSourceError exception. If multiple update attempts need
/// to be performed concurrently (and if the underlying database allows
/// such operation), separate \c DatabaseAccessor instance must be
/// created.
///
/// \note The underlying database may not allow concurrent updates to
/// the same database instance even if different "connections" (or
/// something similar specific to the database implementation) are used
/// for different sets of updates. For example, it doesn't seem to be
/// possible for SQLite3 unless different databases are used. MySQL
/// allows concurrent updates to different tables of the same database,
/// but a specific operation may block others. As such, this interface
/// doesn't require derived classes to allow concurrent updates with
/// multiple \c DatabaseAccessor instances; however, the implementation
/// is encouraged to do the best for making it more likely to succeed
/// as long as the underlying database system allows concurrent updates.
///
/// This method returns a pair of \c bool and \c int. Its first element
/// indicates whether the given name of zone is found. If it's false,
/// the transaction isn't considered to be started; a subsequent call to
/// this method with an existing zone name should succeed. Likewise,
/// if a call to this method results in an exception, the transaction
/// isn't considered to be started. Note also that if the zone is not
/// found this method doesn't try to create a new one in the database.
/// It must have been created by some other means beforehand.
///
/// The second element is the internal zone ID used for subsequent
/// updates. Depending on implementation details of the actual derived
/// class method, it may be different from the one returned by
/// \c getZone(); for example, a specific implementation may use a
/// completely new zone ID when \c replace is true.
///
/// \exception DataSourceError Duplicate call to this method, or some
/// internal database related error.
///
/// \param zone_name A string representation of the zone name to be updated
/// \param replace Whether to replace the entire zone (see above)
///
/// \return A pair of bool and int, indicating whether the specified zone
/// exists and (if so) the zone ID to be used for the update, respectively.
virtual std::pair<bool, int> startUpdateZone(const std::string& zone_name,
bool replace) = 0;
/// Add a single record to the zone to be updated.
///
/// This method provides a simple interface to insert a new record
/// (a database "row") to the zone in the update context started by
/// \c startUpdateZone(). The zone to which the record to be added
/// is the one specified at the time of the \c startUpdateZone() call.
///
/// A successful call to \c startUpdateZone() must have preceded to
/// this call; otherwise a \c DataSourceError exception will be thrown.
///
/// The row is defined as a vector of strings that has exactly
/// ADD_COLUMN_COUNT number of elements. See AddRecordColumns for
/// the semantics of each element.
///
/// Derived class methods are not required to check whether the given
/// values in \c columns are valid in terms of the expected semantics;
/// in general, it's the caller's responsibility.
/// For example, TTLs would normally be expected to be a textual
/// representation of decimal numbers, but this interface doesn't require
/// the implementation to perform this level of validation. It may check
/// the values, however, and in that case if it detects an error it
/// should throw a \c DataSourceError exception.
///
/// Likewise, derived class methods are not required to detect any
/// duplicate record that is already in the zone.
///
/// \note The underlying database schema may not have a trivial mapping
/// from this style of definition of rows to actual database records.
/// It's the implementation's responsibility to implement the mapping
/// in the actual derived method.
///
/// \exception DataSourceError Invalid call without starting a transaction,
/// or other internal database error.
///
/// \param columns An array of strings that defines a record to be added
/// to the zone.
virtual void addRecordToZone(
const std::string (&columns)[ADD_COLUMN_COUNT]) = 0;
/// Delete a single record from the zone to be updated.
///
/// This method provides a simple interface to delete a record
/// (a database "row") from the zone in the update context started by
/// \c startUpdateZone(). The zone from which the record to be deleted
/// is the one specified at the time of the \c startUpdateZone() call.
///
/// A successful call to \c startUpdateZone() must have preceded to
/// this call; otherwise a \c DataSourceError exception will be thrown.
///
/// The record to be deleted is specified by a vector of strings that has
/// exactly DEL_PARAM_COUNT number of elements. See DeleteRecordParams
/// for the semantics of each element.
///
/// \note In IXFR, TTL may also be specified, but we intentionally
/// ignore that in this interface, because it's not guaranteed
/// that all records have the same TTL (unlike the RRset
/// assumption) and there can even be multiple records for the
/// same name, type and rdata with different TTLs. If we only
/// delete one of them, subsequent lookup will still return a
/// positive answer, which would be confusing. It's a higher
/// layer's responsibility to check if there is at least one
/// record in the database that has the given TTL.
///
/// Like \c addRecordToZone, derived class methods are not required to
/// validate the semantics of the given parameters or to check if there
/// is a record that matches the specified parameter; if there isn't
/// it simply ignores the result.
///
/// \exception DataSourceError Invalid call without starting a transaction,
/// or other internal database error.
///
/// \param params An array of strings that defines a record to be deleted
/// from the zone.
virtual void deleteRecordInZone(
const std::string (&params)[DEL_PARAM_COUNT]) = 0;
/// Commit updates to the zone.
///
/// This method completes a transaction of making updates to the zone
/// in the context started by startUpdateZone.
///
/// A successful call to \c startUpdateZone() must have preceded to
/// this call; otherwise a \c DataSourceError exception will be thrown.
/// Once this method successfully completes, the transaction isn't
/// considered to exist any more. So a new transaction can now be
/// started. On the other hand, a duplicate call to this method after
/// a successful completion of it is invalid and should result in
/// a \c DataSourceError exception.
///
/// If some internal database error happens, a \c DataSourceError
/// exception must be thrown. In that case the transaction is still
/// considered to be valid; the caller must explicitly rollback it
/// or (if it's confident that the error is temporary) try to commit it
/// again.
///
/// \exception DataSourceError Call without a transaction, duplicate call
/// to the method or internal database error.
virtual void commitUpdateZone() = 0;
/// Rollback updates to the zone made so far.
///
/// This method rollbacks a transaction of making updates to the zone
/// in the context started by startUpdateZone. When it succeeds
/// (it normally should, but see below), the underlying database should
/// be reverted to the point before performing the corresponding
/// \c startUpdateZone().
///
/// A successful call to \c startUpdateZone() must have preceded to
/// this call; otherwise a \c DataSourceError exception will be thrown.
/// Once this method successfully completes, the transaction isn't
/// considered to exist any more. So a new transaction can now be
/// started. On the other hand, a duplicate call to this method after
/// a successful completion of it is invalid and should result in
/// a \c DataSourceError exception.
///
/// Normally this method should not fail. But it may not always be
/// possible to guarantee it depending on the characteristics of the
/// underlying database system. So this interface doesn't require the
/// actual implementation for the error free property. But if a specific
/// implementation of this method can fail, it is encouraged to document
/// when that can happen with its implication.
///
/// \exception DataSourceError Call without a transaction, duplicate call
/// to the method or internal database error.
virtual void rollbackUpdateZone() = 0;
/**
* \brief Returns a string identifying this dabase backend
*
......@@ -338,18 +553,19 @@ public:
* applications shouldn't need it.
*/
int zone_id() const { return (zone_id_); }
/**
* \brief The database.
* \brief The database accessor.
*
* This function provides the database stored inside as
* This function provides the database accessor stored inside as
* passed to the constructor. This is meant for testing purposes and
* normal applications shouldn't need it.
*/
const DatabaseAccessor& database() const {
return (*database_);
const DatabaseAccessor& getAccessor() const {
return (*accessor_);
}
private:
boost::shared_ptr<DatabaseAccessor> database_;
boost::shared_ptr<DatabaseAccessor> accessor_;
const int zone_id_;
const isc::dns::Name origin_;
/**
......@@ -408,6 +624,7 @@ public:
*/
bool hasSubdomains(const std::string& name);
};
/**
* \brief Find a zone in the database
*
......@@ -444,8 +661,8 @@ public:
virtual ZoneIteratorPtr getIterator(const isc::dns::Name& name) const;
private:
/// \brief Our database.
const boost::shared_ptr<DatabaseAccessor> database_;
/// \brief The accessor to our database.
const boost::shared_ptr<DatabaseAccessor> accessor_;
};
}
......
This diff is collapsed.
......@@ -53,8 +53,8 @@ struct SQLite3Parameters;
* According to the design, it doesn't interpret the data in any way, it just
* provides unified access to the DB.
*/
class SQLite3Database : public DatabaseAccessor,
public boost::enable_shared_from_this<SQLite3Database> {
class SQLite3Accessor : public DatabaseAccessor,
public boost::enable_shared_from_this<SQLite3Accessor> {
public:
/**
* \brief Constructor
......@@ -69,14 +69,14 @@ public:
* file can contain multiple classes of data, single database can
* provide only one class).
*/
SQLite3Database(const std::string& filename,
SQLite3Accessor(const std::string& filename,
const isc::dns::RRClass& rrclass);
/**
* \brief Destructor
*
* Closes the database.
*/
~SQLite3Database();
~SQLite3Accessor();
/**
* \brief Look up a zone
......@@ -121,6 +121,33 @@ public:
*/
virtual IteratorContextPtr getAllRecords(int id) const;
virtual std::pair<bool, int> startUpdateZone(const std::string& zone_name,
bool replace);
/// \note we are quite impatient here: it's quite possible that the COMMIT
/// fails due to other process performing SELECT on the same database
/// (consider the case where COMMIT is done by xfrin or dynamic update
/// server while an authoritative server is busy reading the DB).
/// In a future version we should probably need to introduce some retry
/// attempt and/or increase timeout before giving up the COMMIT, even
/// if it still doesn't guarantee 100% success. Right now this
/// implementation throws a \c DataSourceError exception in such a case.
virtual void commitUpdateZone();
/// \note In SQLite3 rollback can fail if there's another unfinished
/// statement is performed for the same database structure.
/// Although it's not expected to happen in our expected usage, it's not
/// guaranteed to be prevented at the API level. If it ever happens, this
/// method throws a \c DataSourceError exception. It should be
/// considered a bug of the higher level application program.
virtual void rollbackUpdateZone();
virtual void addRecordToZone(
const std::string (&columns)[ADD_COLUMN_COUNT]);
virtual void deleteRecordInZone(
const std::string (&params)[DEL_PARAM_COUNT]);
/// The SQLite3 implementation of this method returns a string starting
/// with a fixed prefix of "sqlite3_" followed by the DB file name
/// removing any path name. For example, for the DB file
......@@ -146,4 +173,8 @@ private:
}
}
#endif
#endif // __DATASRC_SQLITE3_CONNECTION_H
// Local Variables:
// mode: c++
// End:
SUBDIRS = . testdata
AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
AM_CPPFLAGS += -I$(top_builddir)/src/lib/dns -I$(top_srcdir)/src/lib/dns
AM_CPPFLAGS += $(BOOST_INCLUDES)
AM_CPPFLAGS += $(SQLITE_CFLAGS)
AM_CPPFLAGS += -DTEST_DATA_DIR=\"$(srcdir)/testdata\"
AM_CPPFLAGS += -DTEST_DATA_BUILD_DIR=\"$(builddir)/testdata\"
AM_CPPFLAGS += -DTEST_DATA_DIR=\"$(abs_srcdir)/testdata\"
AM_CPPFLAGS += -DTEST_DATA_BUILDDIR=\"$(abs_builddir)/testdata\"
AM_CPPFLAGS += -DINSTALL_PROG=\"$(abs_top_srcdir)/install-sh\"
AM_CXXFLAGS = $(B10_CXXFLAGS)
......
......@@ -58,6 +58,15 @@ public:
}
}
virtual std::pair<bool, int> startUpdateZone(const std::string&, bool) {
// return dummy value. unused anyway.
return (pair<bool, int>(true, 0));
}
virtual void commitUpdateZone() {}
virtual void rollbackUpdateZone() {}
virtual void addRecordToZone(const string (&)[ADD_COLUMN_COUNT]) {}
virtual void deleteRecordInZone(const string (&)[DEL_PARAM_COUNT]) {}
virtual const std::string& getDBName() const {
return (database_name_);
}
......@@ -498,12 +507,12 @@ public:
* times per test.
*/
void createClient() {
current_database_ = new MockAccessor();
current_accessor_ = new MockAccessor();
client_.reset(new DatabaseClient(shared_ptr<DatabaseAccessor>(
current_database_)));
current_accessor_)));
}
// Will be deleted by client_, just keep the current value for comparison.
MockAccessor* current_database_;
MockAccessor* current_accessor_;
shared_ptr<DatabaseClient> client_;
const std::string database_name_;
......@@ -518,7 +527,7 @@ public:
ASSERT_NE(shared_ptr<DatabaseClient::Finder>(), finder) <<
"Wrong type of finder";
EXPECT_EQ(42, finder->zone_id());