]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[1008-move-database-schema-version-check-to-database-libraries] Moved getVersion...
authorFrancis Dupont <fdupont@isc.org>
Thu, 21 Nov 2019 03:07:29 +0000 (04:07 +0100)
committerFrancis Dupont <fdupont@isc.org>
Wed, 4 Dec 2019 13:33:09 +0000 (14:33 +0100)
15 files changed:
src/hooks/dhcp/mysql_cb/mysql_cb_impl.cc
src/lib/cql/cql_connection.cc
src/lib/cql/cql_connection.h
src/lib/dhcpsrv/cql_host_data_source.cc
src/lib/dhcpsrv/cql_lease_mgr.cc
src/lib/dhcpsrv/cql_lease_mgr.h
src/lib/dhcpsrv/mysql_host_data_source.cc
src/lib/dhcpsrv/mysql_lease_mgr.cc
src/lib/dhcpsrv/pgsql_lease_mgr.cc
src/lib/dhcpsrv/pgsql_lease_mgr.h
src/lib/mysql/mysql_connection.cc
src/lib/mysql/mysql_connection.h
src/lib/mysql/tests/mysql_connection_unittest.cc
src/lib/pgsql/pgsql_connection.cc
src/lib/pgsql/pgsql_connection.h

index b3a9a32a5e60ee3db7135ab64772ae5512f46ac7..8598fa49283fb14a3e530e302b7df0310d631e7b 100644 (file)
@@ -44,19 +44,20 @@ ScopedAuditRevision::~ScopedAuditRevision() {
 MySqlConfigBackendImpl::
 MySqlConfigBackendImpl(const DatabaseConnection::ParameterMap& parameters)
     : conn_(parameters), audit_revision_created_(false) {
-    // Open the database.
-    conn_.openDatabase();
-
-    // Test schema version before we try to prepare statements.
+    // Test schema version first.
     std::pair<uint32_t, uint32_t> code_version(MYSQL_SCHEMA_VERSION_MAJOR,
                                                MYSQL_SCHEMA_VERSION_MINOR);
-/*    std::pair<uint32_t, uint32_t> db_version = getVersion();
+    std::pair<uint32_t, uint32_t> db_version =
+        MySqlConnection::getVersion(parameters);
     if (code_version != db_version) {
         isc_throw(DbOpenError, "MySQL schema version mismatch: need version: "
                   << code_version.first << "." << code_version.second
                   << " found version:  " << db_version.first << "."
                   << db_version.second);
-    } */
+    }
+
+    // Open the database.
+    conn_.openDatabase();
 
     // Enable autocommit. In case transaction is explicitly used, this
     // setting will be overwritten for the transaction. However, there are
index 481c6e9f4cba6bd9e957a30ff564989ea54d467a..f4d61fe62ade2cd8740a5abfb790c6269fcf62ca 100644 (file)
@@ -75,6 +75,21 @@ CqlConnection::~CqlConnection() {
     }
 }
 
+std::pair<uint32_t, uint32_t>
+CqlConnection::getVersion(const ParameterMap& parameters) {
+    // Get a connection.
+    CqlConnection conn(parameters);
+
+    // Open the database.
+    conn.openDatabase();
+
+    // Prepare statement.
+    conn.prepareStatements(CqlVersionExchange::tagged_statements_);
+
+    std::unique_ptr<CqlVersionExchange> version_exchange(new CqlVersionExchange());
+    return version_exchange->retrieveVersion(conn);
+}
+
 CassConsistency CqlConnection::parseConsistency(std::string value) {
     static std::map<std::string, CassConsistency> consistency_map {
         {"any", CASS_CONSISTENCY_ANY},
index f14400badfa0aec13609eb23c184ec8d57b09b12..eaa8ee8d981a8f54f24ca8074b10dd21858d53b3 100644 (file)
@@ -127,6 +127,19 @@ public:
     /// @brief Destructor
     virtual ~CqlConnection();
 
+    /// @brief Get the schema version.
+    ///
+    /// @param parameters A data structure relating keywords and values
+    ///        concerned with the database.
+    ///
+    /// @return Version number as a pair of unsigned integers.  "first" is the
+    ///         major version number, "second" the minor number.
+    ///
+    /// @throw isc::db::DbOperationError An operation on the open database has
+    ///        failed.
+    static std::pair<uint32_t, uint32_t>
+    getVersion(const ParameterMap& parameters);
+
     /// @brief Prepare statements
     ///
     /// Creates the prepared statements for all of the CQL statements used
index 00988ffb101f554d9e4ad24f5419f6336d3e7db3..20c555e10486c0eba18e7c4b18ad4d87ccb503cb 100644 (file)
@@ -2320,6 +2320,9 @@ protected:
                             HostPtr& target_host) const;
 
 private:
+    /// @brief Parameters
+    db::DatabaseConnection::ParameterMap parameters_;
+
     /// @brief CQL connection
     mutable CqlConnection dbconn_;
 };  // class CqlHostDataSourceImpl
@@ -2366,14 +2369,8 @@ operator==(const HostKey& key1, const HostKey& key2) {
 }
 
 CqlHostDataSourceImpl::CqlHostDataSourceImpl(const CqlConnection::ParameterMap& parameters)
-    : dbconn_(parameters) {
-    // Open the database.
-    dbconn_.openDatabase();
-
-    // Prepare the version exchange first.
-    dbconn_.prepareStatements(CqlVersionExchange::tagged_statements_);
-
-    // Validate the schema version.
+    : parameters_(parameters), dbconn_(parameters) {
+    // Validate the schema version first.
     std::pair<uint32_t, uint32_t> code_version(CQL_SCHEMA_VERSION_MAJOR,
                                                CQL_SCHEMA_VERSION_MINOR);
     std::pair<uint32_t, uint32_t> db_version = getVersion();
@@ -2384,6 +2381,9 @@ CqlHostDataSourceImpl::CqlHostDataSourceImpl(const CqlConnection::ParameterMap&
                   << db_version.second);
     }
 
+    // Open the database.
+    dbconn_.openDatabase();
+
     // Prepare all possible statements.
     dbconn_.prepareStatements(CqlHostExchange::tagged_statements_);
 }
@@ -2748,8 +2748,7 @@ CqlHostDataSourceImpl::getName() const {
 
 VersionPair
 CqlHostDataSourceImpl::getVersion() const {
-    std::unique_ptr<CqlVersionExchange> version_exchange(new CqlVersionExchange());
-    return (version_exchange->retrieveVersion(dbconn_));
+    return CqlConnection::getVersion(parameters_);
 }
 
 bool
index 55913f554d95e86dcd2e79b865f07a70ff21d4a1..0fc485f3f3b1f43dba6bb0caafbc56e9a2db2b2a 100644 (file)
@@ -2029,13 +2029,8 @@ CqlLeaseStatsQuery::executeSelect(const CqlConnection& connection, const AnyArra
 }
 
 CqlLeaseMgr::CqlLeaseMgr(const DatabaseConnection::ParameterMap &parameters)
-    : LeaseMgr(), dbconn_(parameters) {
-    dbconn_.openDatabase();
-
-    // Prepare the version exchange first.
-    dbconn_.prepareStatements(CqlVersionExchange::tagged_statements_);
-
-    // Validate the schema version.
+  : LeaseMgr(), parameters_(parameters), dbconn_(parameters) {
+    // Validate the schema version first.
     std::pair<uint32_t, uint32_t> code_version(CQL_SCHEMA_VERSION_MAJOR,
                                                CQL_SCHEMA_VERSION_MINOR);
     std::pair<uint32_t, uint32_t> db_version = getVersion();
@@ -2046,6 +2041,9 @@ CqlLeaseMgr::CqlLeaseMgr(const DatabaseConnection::ParameterMap &parameters)
                   << db_version.second);
     }
 
+    // Open the database.
+    dbconn_.openDatabase();
+
     // Now prepare the rest of the exchanges.
     dbconn_.prepareStatements(CqlLease4Exchange::tagged_statements_);
     dbconn_.prepareStatements(CqlLease6Exchange::tagged_statements_);
@@ -2744,8 +2742,7 @@ VersionPair
 CqlLeaseMgr::getVersion() const {
     LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_CQL_GET_VERSION);
 
-    std::unique_ptr<CqlVersionExchange> version_exchange(new CqlVersionExchange());
-    return version_exchange->retrieveVersion(dbconn_);
+    return CqlConnection::getVersion(parameters_);
 }
 
 void
index 4760a3134a7b8a8dfa8e8ad282e36b93903394fd..1736a8eb152f0af2edaf1b18d3928994a5f2b805 100644 (file)
@@ -578,6 +578,9 @@ public:
     virtual void rollback() override;
 
 private:
+    /// @brief Connection parameters
+    db::DatabaseConnection::ParameterMap parameters_;
+
     /// @brief Database connection object
     mutable db::CqlConnection dbconn_;
 };
index 53400708819bdca4a002c5cbda639bb76d15b794..942e1de06c47388f6ccb2d3555a56048b80d8ae3 100644 (file)
@@ -1948,11 +1948,9 @@ public:
 
     /// @brief Returns backend version.
     ///
-    /// The method is called by the constructor after opening the database
-    /// but prior to preparing SQL statements, to verify that the schema version
-    /// is correct. Thus it must not rely on a pre-prepared statement or
-    /// formal statement execution error checking.
-    //
+    /// The method is called by the constructor before opening the database
+    /// to verify that the schema version is correct.
+    ///
     /// @return Version number stored in the database, as a pair of unsigned
     ///         integers. "first" is the major version number, "second" the
     ///         minor number.
@@ -2097,6 +2095,9 @@ public:
     /// or dhcp6_options table.
     boost::shared_ptr<MySqlOptionExchange> host_option_exchange_;
 
+    /// @brief The parameters
+    db::DatabaseConnection::ParameterMap parameters_;
+
     /// @brief MySQL connection
     MySqlConnection conn_;
 
@@ -2481,13 +2482,11 @@ MySqlHostDataSourceImpl(const MySqlConnection::ParameterMap& parameters)
                                                      DHCP4_AND_DHCP6)),
       host_ipv6_reservation_exchange_(new MySqlIPv6ReservationExchange()),
       host_option_exchange_(new MySqlOptionExchange()),
+      parameters_(parameters),
       conn_(parameters),
       is_readonly_(false) {
 
-    // Open the database.
-    conn_.openDatabase();
-
-    // Test schema version before we try to prepare statements.
+    // Test schema version first.
     std::pair<uint32_t, uint32_t> code_version(MYSQL_SCHEMA_VERSION_MAJOR,
                                                MYSQL_SCHEMA_VERSION_MINOR);
     std::pair<uint32_t, uint32_t> db_version = getVersion();
@@ -2498,6 +2497,9 @@ MySqlHostDataSourceImpl(const MySqlConnection::ParameterMap& parameters)
                   << db_version.second);
     }
 
+    // Open the database.
+    conn_.openDatabase();
+
     // Enable autocommit. In case transaction is explicitly used, this
     // setting will be overwritten for the transaction. However, there are
     // cases when lack of autocommit could cause transactions to hang
@@ -2551,62 +2553,9 @@ MySqlHostDataSourceImpl::getVersion() const {
     LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
               DHCPSRV_MYSQL_HOST_DB_GET_VERSION);
 
-    // Allocate a new statement.
-    MYSQL_STMT *stmt = mysql_stmt_init(conn_.mysql_);
-    if (stmt == NULL) {
-        isc_throw(DbOperationError, "unable to allocate MySQL prepared "
-                  "statement structure, reason: " << mysql_error(conn_.mysql_));
-    }
-
-    // Prepare the statement from SQL text.
-    const char* version_sql = "SELECT version, minor FROM schema_version";
-    int status = mysql_stmt_prepare(stmt, version_sql, strlen(version_sql));
-    if (status != 0) {
-        isc_throw(DbOperationError, "unable to prepare MySQL statement <"
-                  << version_sql << ">, reason: " << mysql_errno(conn_.mysql_));
-    }
-
-    // Execute the prepared statement.
-    if (mysql_stmt_execute(stmt) != 0) {
-        isc_throw(DbOperationError, "cannot execute schema version query <"
-                  << version_sql << ">, reason: " << mysql_errno(conn_.mysql_));
-    }
-
-    // Bind the output of the statement to the appropriate variables.
-    MYSQL_BIND bind[2];
-    memset(bind, 0, sizeof(bind));
-
-    uint32_t major;
-    bind[0].buffer_type = MYSQL_TYPE_LONG;
-    bind[0].is_unsigned = 1;
-    bind[0].buffer = &major;
-    bind[0].buffer_length = sizeof(major);
-
-    uint32_t minor;
-    bind[1].buffer_type = MYSQL_TYPE_LONG;
-    bind[1].is_unsigned = 1;
-    bind[1].buffer = &minor;
-    bind[1].buffer_length = sizeof(minor);
-
-    if (mysql_stmt_bind_result(stmt, bind)) {
-        isc_throw(DbOperationError, "unable to bind result set for <"
-                  << version_sql << ">, reason: " << mysql_errno(conn_.mysql_));
-    }
-
-    // Fetch the data.
-    if (mysql_stmt_fetch(stmt)) {
-        mysql_stmt_close(stmt);
-        isc_throw(DbOperationError, "unable to bind result set for <"
-                  << version_sql << ">, reason: " << mysql_errno(conn_.mysql_));
-    }
-
-    // Discard the statement and its resources
-    mysql_stmt_close(stmt);
-
-    return (std::make_pair(major, minor));
+    return (MySqlConnection::getVersion(parameters_));
 }
 
-
 void
 MySqlHostDataSourceImpl::addStatement(StatementIndex stindex,
                                       std::vector<MYSQL_BIND>& bind) {
index 821b33e42daa1471b92fb9179b5d5825c6aee959..49cae6d11362ad47f70aa4b70faa9f2334bf539a 100644 (file)
@@ -2961,65 +2961,7 @@ MySqlLeaseMgr::getVersion() const {
     LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
               DHCPSRV_MYSQL_GET_VERSION);
 
-    // Get a connection.
-    MySqlConnection conn(parameters_);
-
-    // Open the database.
-    conn.openDatabase();
-
-    // Allocate a new statement.
-    MYSQL_STMT *stmt = mysql_stmt_init(conn.mysql_);
-    if (stmt == NULL) {
-        isc_throw(DbOperationError, "unable to allocate MySQL prepared "
-                "statement structure, reason: " << mysql_error(conn.mysql_));
-    }
-
-    // Prepare the statement from SQL text.
-    const char* version_sql = "SELECT version, minor FROM schema_version";
-    int status = mysql_stmt_prepare(stmt, version_sql, strlen(version_sql));
-    if (status != 0) {
-        isc_throw(DbOperationError, "unable to prepare MySQL statement <"
-                  << version_sql << ">, reason: " << mysql_error(conn.mysql_));
-    }
-
-    // Execute the prepared statement.
-    if (mysql_stmt_execute(stmt) != 0) {
-        isc_throw(DbOperationError, "cannot execute schema version query <"
-                  << version_sql << ">, reason: " << mysql_errno(conn.mysql_));
-    }
-
-    // Bind the output of the statement to the appropriate variables.
-    MYSQL_BIND bind[2];
-    memset(bind, 0, sizeof(bind));
-
-    uint32_t major;
-    bind[0].buffer_type = MYSQL_TYPE_LONG;
-    bind[0].is_unsigned = 1;
-    bind[0].buffer = &major;
-    bind[0].buffer_length = sizeof(major);
-
-    uint32_t minor;
-    bind[1].buffer_type = MYSQL_TYPE_LONG;
-    bind[1].is_unsigned = 1;
-    bind[1].buffer = &minor;
-    bind[1].buffer_length = sizeof(minor);
-
-    if (mysql_stmt_bind_result(stmt, bind)) {
-        isc_throw(DbOperationError, "unable to bind result set for <"
-                << version_sql << ">, reason: " << mysql_errno(conn.mysql_));
-    }
-
-    // Fetch the data.
-    if (mysql_stmt_fetch(stmt)) {
-        mysql_stmt_close(stmt);
-        isc_throw(DbOperationError, "unable to bind result set for <"
-                << version_sql << ">, reason: " << mysql_errno(conn.mysql_));
-    }
-
-    // Discard the statement and its resources
-    mysql_stmt_close(stmt);
-
-    return (std::make_pair(major, minor));
+    return (MySqlConnection::getVersion(parameters_));
 }
 
 void
index 1ade37364974a196e1c400e8a6e0592f1b6b69ff..3ca1e3ed1643721047fc0d325950abe9df2e3afc 100644 (file)
@@ -1115,9 +1115,8 @@ protected:
 
 PgSqlLeaseMgr::PgSqlLeaseMgr(const DatabaseConnection::ParameterMap& parameters)
     : LeaseMgr(), exchange4_(new PgSqlLease4Exchange()),
-    exchange6_(new PgSqlLease6Exchange()), conn_(parameters) {
-    conn_.openDatabase();
-
+      exchange6_(new PgSqlLease6Exchange()), parameters_(parameters),
+      conn_(parameters) {
     // Validate schema version first.
     std::pair<uint32_t, uint32_t> code_version(PG_SCHEMA_VERSION_MAJOR,
                                                PG_SCHEMA_VERSION_MINOR);
@@ -1130,6 +1129,9 @@ PgSqlLeaseMgr::PgSqlLeaseMgr(const DatabaseConnection::ParameterMap& parameters)
                       << db_version.second);
     }
 
+    // Open the database.
+    conn_.openDatabase();
+
     // Now prepare the SQL statements.
     int i = 0;
     for( ; tagged_statements[i].text != NULL ; ++i) {
@@ -1929,25 +1931,7 @@ PgSqlLeaseMgr::getVersion() const {
     LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
               DHCPSRV_PGSQL_GET_VERSION);
 
-    const char* version_sql =  "SELECT version, minor FROM schema_version;";
-    PgSqlResult r(PQexec(conn_, version_sql));
-    if(PQresultStatus(r) != PGRES_TUPLES_OK) {
-        isc_throw(DbOperationError, "unable to execute PostgreSQL statement <"
-                  << version_sql << ", reason: " << PQerrorMessage(conn_));
-    }
-
-    istringstream tmp;
-    uint32_t version;
-    tmp.str(PQgetvalue(r, 0, 0));
-    tmp >> version;
-    tmp.str("");
-    tmp.clear();
-
-    uint32_t minor;
-    tmp.str(PQgetvalue(r, 0, 1));
-    tmp >> minor;
-
-    return (make_pair(version, minor));
+    return (PgSqlConnection::getVersion(parameters_));
 }
 
 void
index cd1ccbf74d041911f85906732047b5b9e335ccc2..8fdbe9a75ebaaf0feb014d1bde471a3c05a7bcf7 100644 (file)
@@ -770,6 +770,9 @@ private:
     boost::scoped_ptr<PgSqlLease4Exchange> exchange4_; ///< Exchange object
     boost::scoped_ptr<PgSqlLease6Exchange> exchange6_; ///< Exchange object
 
+    /// The parameters.
+    db::DatabaseConnection::ParameterMap parameters_;
+
     /// PostgreSQL connection handle
     db::PgSqlConnection conn_;
 };
index 8efc9a06ca13792ff7279b0f02a56803d54cc764..543cca74b1652debbd68532895cf4a441dc51d05 100644 (file)
@@ -212,6 +212,70 @@ MySqlConnection::openDatabase() {
     }
 }
 
+// Get schema version.
+
+std::pair<uint32_t, uint32_t>
+MySqlConnection::getVersion(const ParameterMap& parameters) {
+    // Get a connection.
+    MySqlConnection conn(parameters);
+
+    // Open the database.
+    conn.openDatabase();
+
+    // Allocate a new statement.
+    MYSQL_STMT *stmt = mysql_stmt_init(conn.mysql_);
+    if (stmt == NULL) {
+        isc_throw(DbOperationError, "unable to allocate MySQL prepared "
+                "statement structure, reason: " << mysql_error(conn.mysql_));
+    }
+
+    // Prepare the statement from SQL text.
+    const char* version_sql = "SELECT version, minor FROM schema_version";
+    int status = mysql_stmt_prepare(stmt, version_sql, strlen(version_sql));
+    if (status != 0) {
+        isc_throw(DbOperationError, "unable to prepare MySQL statement <"
+                  << version_sql << ">, reason: " << mysql_error(conn.mysql_));
+    }
+
+    // Execute the prepared statement.
+    if (mysql_stmt_execute(stmt) != 0) {
+        isc_throw(DbOperationError, "cannot execute schema version query <"
+                  << version_sql << ">, reason: " << mysql_errno(conn.mysql_));
+    }
+
+    // Bind the output of the statement to the appropriate variables.
+    MYSQL_BIND bind[2];
+    memset(bind, 0, sizeof(bind));
+
+    uint32_t major;
+    bind[0].buffer_type = MYSQL_TYPE_LONG;
+    bind[0].is_unsigned = 1;
+    bind[0].buffer = &major;
+    bind[0].buffer_length = sizeof(major);
+
+    uint32_t minor;
+    bind[1].buffer_type = MYSQL_TYPE_LONG;
+    bind[1].is_unsigned = 1;
+    bind[1].buffer = &minor;
+    bind[1].buffer_length = sizeof(minor);
+
+    if (mysql_stmt_bind_result(stmt, bind)) {
+        isc_throw(DbOperationError, "unable to bind result set for <"
+                << version_sql << ">, reason: " << mysql_errno(conn.mysql_));
+    }
+
+    // Fetch the data.
+    if (mysql_stmt_fetch(stmt)) {
+        mysql_stmt_close(stmt);
+        isc_throw(DbOperationError, "unable to bind result set for <"
+                << version_sql << ">, reason: " << mysql_errno(conn.mysql_));
+    }
+
+    // Discard the statement and its resources
+    mysql_stmt_close(stmt);
+
+    return (std::make_pair(major, minor));
+}
 
 // Prepared statement setup.  The textual form of an SQL statement is stored
 // in a vector of strings (text_statements_) and is used in the output of
index 929fbc16e56db15c69aa97d7c75d3ed83fda3ddf..9e540f99a565003e7c4c5f4df99547461174aa2e 100644 (file)
@@ -210,6 +210,19 @@ public:
     /// @brief Destructor
     virtual ~MySqlConnection();
 
+    /// @brief Get the schema version.
+    ///
+    /// @param parameters A data structure relating keywords and values
+    ///        concerned with the database.
+    ///
+    /// @return Version number as a pair of unsigned integers.  "first" is the
+    ///         major version number, "second" the minor number.
+    ///
+    /// @throw isc::db::DbOperationError An operation on the open database has
+    ///        failed.
+    static std::pair<uint32_t, uint32_t>
+    getVersion(const ParameterMap& parameters);
+
     /// @brief Prepare Single Statement
     ///
     /// Creates a prepared statement from the text given and adds it to the
index 7d0a04d674cd4c594a1755fd9ad630aded40aa86..53759777a6ebc2f12ff677eb5ba27d69609ec48b 100644 (file)
@@ -390,4 +390,29 @@ TEST_F(MySqlConnectionTest, deleteByValue) {
     EXPECT_TRUE(deleted);
 }
 
+/// @brief Test fixture class for @c MySqlConnection class methods.
+class MySqlSchemaTest : public ::testing::Test {
+public:
+    /// @brief Constructor.
+    MySqlSchemaTest() {
+        // Ensure we have the proper schema.
+        createMySQLSchema();
+    }
+
+    /// @brief Destructor.
+    virtual ~MySqlSchemaTest() {
+        destroyMySQLSchema();
+    }
+};
+
+/// @brief Check that getVersion() returns the expected version.
+TEST_F(MySqlSchemaTest, checkVersion) {
+    // Check version
+    auto parameters = DatabaseConnection::parse(validMySQLConnectionString());
+    std::pair<uint32_t, uint32_t> version;
+    ASSERT_NO_THROW(version = MySqlConnection::getVersion(parameters));
+    EXPECT_EQ(MYSQL_SCHEMA_VERSION_MAJOR, version.first);
+    EXPECT_EQ(MYSQL_SCHEMA_VERSION_MINOR, version.second);
+}
+
 }
index af98f098cb1468af6300cdb1743326d979fd1dc6..99dd0f080848e0d42f5bb5cc048070bfa22b04c7 100644 (file)
@@ -25,6 +25,8 @@
 #define PGSQL_STATECODE_LEN 5
 #include <utils/errcodes.h>
 
+#include <sstream>
+
 using namespace std;
 
 namespace isc {
@@ -127,6 +129,35 @@ PgSqlConnection::~PgSqlConnection() {
     }
 }
 
+std::pair<uint32_t, uint32_t>
+PgSqlConnection::getVersion(const ParameterMap& parameters) {
+    // Get a connection.
+    PgSqlConnection conn(parameters);
+
+    // Open the database.
+    conn.openDatabase();
+
+    const char* version_sql =  "SELECT version, minor FROM schema_version;";
+    PgSqlResult r(PQexec(conn.conn_, version_sql));
+    if (PQresultStatus(r) != PGRES_TUPLES_OK) {
+        isc_throw(DbOperationError, "unable to execute PostgreSQL statement <"
+                  << version_sql << ", reason: " << PQerrorMessage(conn.conn_));
+    }
+
+    istringstream tmp;
+    uint32_t version;
+    tmp.str(PQgetvalue(r, 0, 0));
+    tmp >> version;
+    tmp.str("");
+    tmp.clear();
+
+    uint32_t minor;
+    tmp.str(PQgetvalue(r, 0, 1));
+    tmp >> minor;
+
+    return (make_pair(version, minor));
+}
+
 void
 PgSqlConnection::prepareStatement(const PgSqlTaggedStatement& statement) {
     // Prepare all statements queries with all known fields datatype
index 339ec7eefccc6d15f25497322db486184878fa1a..ac644a9e75e3f2e1e38a82e76b4d73b593a1522b 100644 (file)
@@ -311,6 +311,19 @@ public:
     /// @brief Destructor
     virtual ~PgSqlConnection();
 
+    /// @brief Get the schema version.
+    ///
+    /// @param parameters A data structure relating keywords and values
+    ///        concerned with the database.
+    ///
+    /// @return Version number as a pair of unsigned integers.  "first" is the
+    ///         major version number, "second" the minor number.
+    ///
+    /// @throw isc::db::DbOperationError An operation on the open database has
+    ///        failed.
+    static std::pair<uint32_t, uint32_t>
+    getVersion(const ParameterMap& parameters);
+
     /// @brief Prepare Single Statement
     ///
     /// Creates a prepared statement from the text given and adds it to the
@@ -318,7 +331,7 @@ public:
     ///
     /// @param statement SQL statement to be prepared.
     ///
-    /// @throw isc::dhcp::DbOperationError An operation on the open database has
+    /// @throw isc::db::DbOperationError An operation on the open database has
     ///        failed.
     void prepareStatement(const PgSqlTaggedStatement& statement);
 
@@ -332,7 +345,7 @@ public:
     /// @param end_statement Pointer to the statement marking end of the
     /// range of statements to be compiled. This last statement is not compiled.
     ///
-    /// @throw isc::dhcp::DbOperationError An operation on the open database has
+    /// @throw isc::db::DbOperationError An operation on the open database has
     ///        failed.
     void prepareStatements(const PgSqlTaggedStatement* start_statement,
                            const PgSqlTaggedStatement* end_statement);
@@ -396,7 +409,7 @@ public:
     /// @param r result of the last PostgreSQL operation
     /// @param statement - tagged statement that was executed
     ///
-    /// @throw isc::dhcp::DbOperationError Detailed PostgreSQL failure
+    /// @throw isc::db::DbOperationError Detailed PostgreSQL failure
     void checkStatementError(const PgSqlResult& r,
                              PgSqlTaggedStatement& statement) const;