"Fossies" - the Fresh Open Source Software Archive

Member "kea-1.6.2/src/lib/mysql/mysql_connection.h" (21 Feb 2020, 25223 Bytes) of package /linux/misc/kea-1.6.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "mysql_connection.h" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 1.7.6_vs_1.7.7.

    1 // Copyright (C) 2012-2020 Internet Systems Consortium, Inc. ("ISC")
    2 //
    3 // This Source Code Form is subject to the terms of the Mozilla Public
    4 // License, v. 2.0. If a copy of the MPL was not distributed with this
    5 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
    6 
    7 #ifndef MYSQL_CONNECTION_H
    8 #define MYSQL_CONNECTION_H
    9 
   10 #include <database/database_connection.h>
   11 #include <database/db_exceptions.h>
   12 #include <database/db_log.h>
   13 #include <exceptions/exceptions.h>
   14 #include <mysql/mysql_binding.h>
   15 #include <mysql/mysql_constants.h>
   16 #include <boost/scoped_ptr.hpp>
   17 #include <mysql.h>
   18 #include <mysqld_error.h>
   19 #include <errmsg.h>
   20 #include <functional>
   21 #include <vector>
   22 #include <stdint.h>
   23 
   24 namespace isc {
   25 namespace db {
   26 
   27 
   28 /// @brief Fetch and Release MySQL Results
   29 ///
   30 /// When a MySQL statement is expected, to fetch the results the function
   31 /// mysql_stmt_fetch() must be called.  As well as getting data, this
   32 /// allocates internal state.  Subsequent calls to mysql_stmt_fetch can be
   33 /// made, but when all the data is retrieved, mysql_stmt_free_result must be
   34 /// called to free up the resources allocated.
   35 ///
   36 /// Created prior to the first fetch, this class's destructor calls
   37 /// mysql_stmt_free_result, so eliminating the need for an explicit release
   38 /// in the method calling mysql_stmt_free_result.  In this way, it guarantees
   39 /// that the resources are released even if the MySqlLeaseMgr method concerned
   40 /// exits via an exception.
   41 
   42 class MySqlFreeResult {
   43 public:
   44 
   45     /// @brief Constructor
   46     ///
   47     /// Store the pointer to the statement for which data is being fetched.
   48     ///
   49     /// Note that according to the MySQL documentation, mysql_stmt_free_result
   50     /// only releases resources if a cursor has been allocated for the
   51     /// statement.  This implies that it is a no-op if none have been.  Either
   52     /// way, any error from mysql_stmt_free_result is ignored. (Generating
   53     /// an exception is not much help, as it will only confuse things if the
   54     /// method calling mysql_stmt_fetch is exiting via an exception.)
   55     MySqlFreeResult(MYSQL_STMT* statement) : statement_(statement)
   56     {}
   57 
   58     /// @brief Destructor
   59     ///
   60     /// Frees up fetch context if a fetch has been successfully executed.
   61     ~MySqlFreeResult() {
   62         (void) mysql_stmt_free_result(statement_);
   63     }
   64 
   65 private:
   66     MYSQL_STMT*     statement_;     ///< Statement for which results are freed
   67 };
   68 
   69 /// @brief MySQL Selection Statements
   70 ///
   71 /// Each statement is associated with an index, which is used to reference the
   72 /// associated prepared statement.
   73 
   74 struct TaggedStatement {
   75     uint32_t index;
   76     const char* text;
   77 };
   78 
   79 /// @brief MySQL Handle Holder
   80 ///
   81 /// Small RAII object for safer initialization, will close the database
   82 /// connection upon destruction.  This means that if an exception is thrown
   83 /// during database initialization, resources allocated to the database are
   84 /// guaranteed to be freed.
   85 ///
   86 /// It makes no sense to copy an object of this class.  After the copy, both
   87 /// objects would contain pointers to the same MySql context object.  The
   88 /// destruction of one would invalid the context in the remaining object.
   89 /// For this reason, the class is declared noncopyable.
   90 class MySqlHolder : public boost::noncopyable {
   91 public:
   92 
   93     /// @brief Constructor
   94     ///
   95     /// Push a call to mysql_library_end() at exit time.
   96     /// Initialize MySql and store the associated context object.
   97     ///
   98     /// @throw DbOpenError Unable to initialize MySql handle.
   99     MySqlHolder() : mysql_(mysql_init(NULL)) {
  100         if (!atexit_) {
  101             atexit([]{ mysql_library_end(); });
  102             atexit_ = true;
  103         }
  104         if (mysql_ == NULL) {
  105             isc_throw(db::DbOpenError, "unable to initialize MySQL");
  106         }
  107     }
  108 
  109     /// @brief Destructor
  110     ///
  111     /// Frees up resources allocated by the initialization of MySql.
  112     ~MySqlHolder() {
  113         if (mysql_ != NULL) {
  114             mysql_close(mysql_);
  115         }
  116         // @note Moved the call to mysql_library_end() to atexit.
  117     }
  118 
  119     /// @brief Conversion Operator
  120     ///
  121     /// Allows the MySqlHolder object to be passed as the context argument to
  122     /// mysql_xxx functions.
  123     operator MYSQL*() const {
  124         return (mysql_);
  125     }
  126 
  127 private:
  128     static bool atexit_; ///< Flag to call atexit once.
  129 
  130     MYSQL* mysql_;       ///< Initialization context
  131 };
  132 
  133 /// @brief Forward declaration to @ref MySqlConnection.
  134 class MySqlConnection;
  135 
  136 /// @brief RAII object representing MySQL transaction.
  137 ///
  138 /// An instance of this class should be created in a scope where multiple
  139 /// INSERT statements should be executed within a single transaction. The
  140 /// transaction is started when the constructor of this class is invoked.
  141 /// The transaction is ended when the @ref MySqlTransaction::commit is
  142 /// explicitly called or when the instance of this class is destroyed.
  143 /// The @ref MySqlTransaction::commit commits changes to the database
  144 /// and the changes remain in the database when the instance of the
  145 /// class is destroyed. If the class instance is destroyed before the
  146 /// @ref MySqlTransaction::commit is called, the transaction is rolled
  147 /// back. The rollback on destruction guarantees that partial data is
  148 /// not stored in the database when there is an error during any
  149 /// of the operations belonging to a transaction.
  150 ///
  151 /// The default MySQL backend configuration enables 'autocommit'.
  152 /// Starting a transaction overrides 'autocommit' setting for this
  153 /// particular transaction only. It does not affect the global 'autocommit'
  154 /// setting for the database connection, i.e. all modifications to the
  155 /// database which don't use transactions will still be auto committed.
  156 class MySqlTransaction : public boost::noncopyable {
  157 public:
  158 
  159     /// @brief Constructor.
  160     ///
  161     /// Starts transaction by making a "START TRANSACTION" query.
  162     ///
  163     /// @param conn MySQL connection to use for the transaction. This
  164     /// connection will be later used to commit or rollback changes.
  165     ///
  166     /// @throw DbOperationError if "START TRANSACTION" query fails.
  167     MySqlTransaction(MySqlConnection& conn);
  168 
  169     /// @brief Destructor.
  170     ///
  171     /// Rolls back the transaction if changes haven't been committed.
  172     ~MySqlTransaction();
  173 
  174     /// @brief Commits transaction.
  175     void commit();
  176 
  177 private:
  178 
  179     /// @brief Holds reference to the MySQL database connection.
  180     MySqlConnection& conn_;
  181 
  182     /// @brief Boolean flag indicating if the transaction has been committed.
  183     ///
  184     /// This flag is used in the class destructor to assess if the
  185     /// transaction should be rolled back.
  186     bool committed_;
  187 };
  188 
  189 
  190 /// @brief Common MySQL Connector Pool
  191 ///
  192 /// This class provides common operations for MySQL database connection
  193 /// used by both MySqlLeaseMgr and MySqlHostDataSource. It manages connecting
  194 /// to the database and preparing compiled statements. Its fields are
  195 /// public, because they are used (both set and retrieved) in classes
  196 /// that use instances of MySqlConnection.
  197 class MySqlConnection : public db::DatabaseConnection {
  198 public:
  199 
  200     /// @brief Function invoked to process fetched row.
  201     typedef std::function<void(MySqlBindingCollection&)> ConsumeResultFun;
  202 
  203     /// @brief Constructor
  204     ///
  205     /// Initialize MySqlConnection object with parameters needed for connection.
  206     MySqlConnection(const ParameterMap& parameters)
  207         : DatabaseConnection(parameters) {
  208     }
  209 
  210     /// @brief Destructor
  211     virtual ~MySqlConnection();
  212 
  213     /// @brief Prepare Single Statement
  214     ///
  215     /// Creates a prepared statement from the text given and adds it to the
  216     /// statements_ vector at the given index.
  217     ///
  218     /// @param index Index into the statements_ vector into which the text
  219     ///        should be placed.  The vector must be big enough for the index
  220     ///        to be valid, else an exception will be thrown.
  221     /// @param text Text of the SQL statement to be prepared.
  222     ///
  223     /// @throw isc::db::DbOperationError An operation on the open database has
  224     ///        failed.
  225     /// @throw isc::InvalidParameter 'index' is not valid for the vector.
  226     void prepareStatement(uint32_t index, const char* text);
  227 
  228     /// @brief Prepare statements
  229     ///
  230     /// Creates the prepared statements for all of the SQL statements used
  231     /// by the MySQL backend.
  232     ///
  233     /// @param start_statement Pointer to the first statement in range of the
  234     /// statements to be compiled.
  235     /// @param end_statement Pointer to the statement marking end of the
  236     /// range of statements to be compiled. This last statement is not compiled.
  237     ///
  238     /// @throw isc::db::DbOperationError An operation on the open database has
  239     ///        failed.
  240     /// @throw isc::InvalidParameter 'index' is not valid for the vector.  This
  241     ///        represents an internal error within the code.
  242     void prepareStatements(const TaggedStatement* start_statement,
  243                            const TaggedStatement* end_statement);
  244 
  245     /// @brief Clears prepared statements and text statements.
  246     void clearStatements();
  247 
  248     /// @brief Open Database
  249     ///
  250     /// Opens the database using the information supplied in the parameters
  251     /// passed to the constructor.
  252     ///
  253     /// @throw NoDatabaseName Mandatory database name not given
  254     /// @throw DbOpenError Error opening the database
  255     void openDatabase();
  256 
  257     ///@{
  258     /// The following methods are used to convert between times and time
  259     /// intervals stored in the Lease object, and the times stored in the
  260     /// database.  The reason for the difference is because in the DHCP server,
  261     /// the cltt (Client Time Since Last Transmission) is the natural data; in
  262     /// the lease file - which may be read by the user - it is the expiry time
  263     /// of the lease.
  264 
  265     /// @brief Convert time_t value to database time.
  266     ///
  267     /// @param input_time A time_t value representing time.
  268     /// @param output_time Reference to MYSQL_TIME object where converted time
  269     ///        will be put.
  270     static
  271     void convertToDatabaseTime(const time_t input_time, MYSQL_TIME& output_time);
  272 
  273     /// @brief Convert Lease Time to Database Times
  274     ///
  275     /// Within the DHCP servers, times are stored as client last transmit time
  276     /// and valid lifetime.  In the database, the information is stored as
  277     /// valid lifetime and "expire" (time of expiry of the lease).  They are
  278     /// related by the equation:
  279     ///
  280     /// - expire = client last transmit time + valid lifetime
  281     ///
  282     /// This method converts from the times in the lease object into times
  283     /// able to be added to the database.
  284     ///
  285     /// @param cltt Client last transmit time
  286     /// @param valid_lifetime Valid lifetime
  287     /// @param expire Reference to MYSQL_TIME object where the expiry time of
  288     ///        the lease will be put.
  289     ///
  290     /// @throw isc::BadValue if the sum of the calculated expiration time is
  291     /// greater than the value of @c LeaseMgr::MAX_DB_TIME.
  292     static
  293     void convertToDatabaseTime(const time_t cltt, const uint32_t valid_lifetime,
  294             MYSQL_TIME& expire);
  295 
  296     /// @brief Convert Database Time to Lease Times
  297     ///
  298     /// Within the database, time is stored as "expire" (time of expiry of the
  299     /// lease) and valid lifetime.  In the DHCP server, the information is
  300     /// stored client last transmit time and valid lifetime.  These are related
  301     /// by the equation:
  302     ///
  303     /// - client last transmit time = expire - valid_lifetime
  304     ///
  305     /// This method converts from the times in the database into times
  306     /// able to be inserted into the lease object.
  307     ///
  308     /// @param expire Reference to MYSQL_TIME object from where the expiry
  309     ///        time of the lease is taken.
  310     /// @param valid_lifetime lifetime of the lease.
  311     /// @param cltt Reference to location where client last transmit time
  312     ///        is put.
  313     static
  314     void convertFromDatabaseTime(const MYSQL_TIME& expire,
  315             uint32_t valid_lifetime, time_t& cltt);
  316     ///@}
  317 
  318     /// @brief Starts Transaction
  319     void startTransaction();
  320 
  321     /// @brief Executes SELECT query using prepared statement.
  322     ///
  323     /// The statement index must point to an existing prepared statement
  324     /// associated with the connection. The @c in_bindings size must match
  325     /// the number of placeholders in the prepared statement. The size of
  326     /// the @c out_bindings must match the number of selected columns. The
  327     /// output bindings must be created and must encapsulate values of
  328     /// the appropriate type, e.g. string, uint32_t etc.
  329     ///
  330     /// This method executes prepared statement using provided bindings and
  331     /// calls @c process_result function for each returned row. The
  332     /// @c process_result function is implemented by the caller and should
  333     /// gather and store each returned row in an external data structure prior
  334     /// to returning because the values in the @c out_bindings will be
  335     /// overwritten by the values of the next returned row when this function
  336     /// is called again.
  337     ///
  338     /// @tparam StatementIndex Type of the statement index enum.
  339     ///
  340     /// @param index Index of the query to be executed.
  341     /// @param in_bindings Input bindings holding values to substitue placeholders
  342     /// in the query.
  343     /// @param [out] out_bindings Output bindings where retrieved data will be
  344     /// stored.
  345     /// @param process_result Pointer to the function to be invoked for each
  346     /// retrieved row. This function consumes the retrieved data from the
  347     /// output bindings.
  348     template<typename StatementIndex>
  349     void selectQuery(const StatementIndex& index,
  350                      const MySqlBindingCollection& in_bindings,
  351                      MySqlBindingCollection& out_bindings,
  352                      ConsumeResultFun process_result) {
  353         // Extract native input bindings.
  354         std::vector<MYSQL_BIND> in_bind_vec;
  355         for (MySqlBindingPtr in_binding : in_bindings) {
  356             in_bind_vec.push_back(in_binding->getMySqlBinding());
  357         }
  358 
  359         int status = 0;
  360         if (!in_bind_vec.empty()) {
  361             // Bind parameters to the prepared statement.
  362             status = mysql_stmt_bind_param(statements_[index],
  363                                            in_bind_vec.empty() ? 0 : &in_bind_vec[0]);
  364             checkError(status, index, "unable to bind parameters for select");
  365         }
  366 
  367         // Bind variables that will receive results as well.
  368         std::vector<MYSQL_BIND> out_bind_vec;
  369         for (MySqlBindingPtr out_binding : out_bindings) {
  370             out_bind_vec.push_back(out_binding->getMySqlBinding());
  371         }
  372         if (!out_bind_vec.empty()) {
  373             status = mysql_stmt_bind_result(statements_[index], &out_bind_vec[0]);
  374             checkError(status, index, "unable to bind result parameters for select");
  375         }
  376 
  377         // Execute query.
  378         status = mysql_stmt_execute(statements_[index]);
  379         checkError(status, index, "unable to execute");
  380 
  381         status = mysql_stmt_store_result(statements_[index]);
  382         checkError(status, index, "unable to set up for storing all results");
  383 
  384         // Fetch results.
  385         MySqlFreeResult fetch_release(statements_[index]);
  386         while ((status = mysql_stmt_fetch(statements_[index])) ==
  387                MLM_MYSQL_FETCH_SUCCESS) {
  388             try {
  389                 // For each returned row call user function which should
  390                 // consume the row and copy the data to a safe place.
  391                 process_result(out_bindings);
  392 
  393             } catch (const std::exception& ex) {
  394                 // Rethrow the exception with a bit more data.
  395                 isc_throw(BadValue, ex.what() << ". Statement is <" <<
  396                           text_statements_[index] << ">");
  397             }
  398         }
  399 
  400         // How did the fetch end?
  401         // If mysql_stmt_fetch return value is equal to 1 an error occurred.
  402         if (status == MLM_MYSQL_FETCH_FAILURE) {
  403             // Error - unable to fetch results
  404             checkError(status, index, "unable to fetch results");
  405 
  406         } else if (status == MYSQL_DATA_TRUNCATED) {
  407             // Data truncated - throw an exception indicating what was at fault
  408             isc_throw(DataTruncated, text_statements_[index]
  409                       << " returned truncated data");
  410         }
  411     }
  412 
  413     /// @brief Executes INSERT prepared statement.
  414     ///
  415     /// The statement index must point to an existing prepared statement
  416     /// associated with the connection. The @c in_bindings size must match
  417     /// the number of placeholders in the prepared statement.
  418     ///
  419     /// This method executes prepared statement using provided bindings to
  420     /// insert data into the database.
  421     ///
  422     /// @tparam StatementIndex Type of the statement index enum.
  423     ///
  424     /// @param index Index of the query to be executed.
  425     /// @param in_bindings Input bindings holding values to substitue placeholders
  426     /// in the query.
  427     template<typename StatementIndex>
  428     void insertQuery(const StatementIndex& index,
  429                      const MySqlBindingCollection& in_bindings) {
  430         std::vector<MYSQL_BIND> in_bind_vec;
  431         for (MySqlBindingPtr in_binding : in_bindings) {
  432             in_bind_vec.push_back(in_binding->getMySqlBinding());
  433         }
  434 
  435         // Bind the parameters to the statement
  436         int status = mysql_stmt_bind_param(statements_[index],
  437                                            in_bind_vec.empty() ? 0 : &in_bind_vec[0]);
  438         checkError(status, index, "unable to bind parameters");
  439 
  440         // Execute the statement
  441         status = mysql_stmt_execute(statements_[index]);
  442 
  443         if (status != 0) {
  444             // Failure: check for the special case of duplicate entry.
  445             if (mysql_errno(mysql_) == ER_DUP_ENTRY) {
  446                 isc_throw(DuplicateEntry, "Database duplicate entry error");
  447             }
  448             // Failure: check for the special case of WHERE returning NULL.
  449             if (mysql_errno(mysql_) == ER_BAD_NULL_ERROR) {
  450                 isc_throw(NullKeyError, "Database bad NULL error");
  451             }
  452             checkError(status, index, "unable to execute");
  453         }
  454     }
  455 
  456     /// @brief Executes UPDATE or DELETE prepared statement and returns
  457     /// the number of affected rows.
  458     ///
  459     /// The statement index must point to an existing prepared statement
  460     /// associated with the connection. The @c in_bindings size must match
  461     /// the number of placeholders in the prepared statement.
  462     ///
  463     /// @tparam StatementIndex Type of the statement index enum.
  464     ///
  465     /// @param index Index of the query to be executed.
  466     /// @param in_bindings Input bindings holding values to substitue placeholders
  467     /// in the query.
  468     ///
  469     /// @return Number of affected rows.
  470     template<typename StatementIndex>
  471     uint64_t updateDeleteQuery(const StatementIndex& index,
  472                                const MySqlBindingCollection& in_bindings) {
  473         std::vector<MYSQL_BIND> in_bind_vec;
  474         for (MySqlBindingPtr in_binding : in_bindings) {
  475             in_bind_vec.push_back(in_binding->getMySqlBinding());
  476         }
  477 
  478         // Bind the parameters to the statement
  479         int status = mysql_stmt_bind_param(statements_[index],
  480                                            in_bind_vec.empty() ? 0 : &in_bind_vec[0]);
  481         checkError(status, index, "unable to bind parameters");
  482 
  483         // Execute the statement
  484         status = mysql_stmt_execute(statements_[index]);
  485 
  486         if (status != 0) {
  487             // Failure: check for the special case of duplicate entry.
  488             if ((mysql_errno(mysql_) == ER_DUP_ENTRY)
  489 #ifdef ER_FOREIGN_DUPLICATE_KEY
  490                 || (mysql_errno(mysql_) == ER_FOREIGN_DUPLICATE_KEY)
  491 #endif
  492 #ifdef ER_FOREIGN_DUPLICATE_KEY_WITH_CHILD_INFO
  493                 || (mysql_errno(mysql_) == ER_FOREIGN_DUPLICATE_KEY_WITH_CHILD_INFO)
  494 #endif
  495 #ifdef ER_FOREIGN_DUPLICATE_KEY_WITHOUT_CHILD_INFO
  496                 || (mysql_errno(mysql_) == ER_FOREIGN_DUPLICATE_KEY_WITHOUT_CHILD_INFO)
  497 #endif
  498                 ) {
  499                 isc_throw(DuplicateEntry, "Database duplicate entry error");
  500             }
  501             checkError(status, index, "unable to execute");
  502         }
  503 
  504         // Let's return how many rows were affected.
  505         return (static_cast<uint64_t>(mysql_stmt_affected_rows(statements_[index])));
  506     }
  507 
  508 
  509     /// @brief Commit Transactions
  510     ///
  511     /// Commits all pending database operations. On databases that don't
  512     /// support transactions, this is a no-op.
  513     ///
  514     /// @throw DbOperationError If the commit failed.
  515     void commit();
  516 
  517     /// @brief Rollback Transactions
  518     ///
  519     /// Rolls back all pending database operations. On databases that don't
  520     /// support transactions, this is a no-op.
  521     ///
  522     /// @throw DbOperationError If the rollback failed.
  523     void rollback();
  524 
  525     /// @brief Check Error and Throw Exception
  526     ///
  527     /// Virtually all MySQL functions return a status which, if non-zero,
  528     /// indicates an error.  This function centralizes the error checking
  529     /// code.
  530     ///
  531     /// It is used to determine whether or not the function succeeded, and
  532     /// in the event of failures, decide whether or not those failures are
  533     /// recoverable.
  534     ///
  535     /// If the error is recoverable, the function will throw a DbOperationError.
  536     /// If the error is deemed unrecoverable, such as a loss of connectivity
  537     /// with the server, the function will call invokeDbLostCallback(). If the
  538     /// invocation returns false then either there is no callback registered
  539     /// or the callback has elected not to attempt to reconnect, and a
  540     /// DbUnrecoverableError is thrown.
  541     ///
  542     /// If the invocation returns true, this indicates the calling layer will
  543     /// attempt recovery, and the function throws a DbOperationError to allow
  544     /// the caller to error handle the failed db access attempt.
  545     ///
  546     /// @param status Status code: non-zero implies an error
  547     /// @param index Index of statement that caused the error
  548     /// @param what High-level description of the error
  549     ///
  550     /// @tparam Enumeration representing index of a statement to which an
  551     /// error pertains.
  552     ///
  553     /// @throw isc::db::DbOperationError An operation on the open database has
  554     ///        failed.
  555     template<typename StatementIndex>
  556     void checkError(const int status, const StatementIndex& index,
  557                     const char* what) const {
  558         if (status != 0) {
  559             switch(mysql_errno(mysql_)) {
  560                 // These are the ones we consider fatal. Remember this method is
  561                 // used to check errors of API calls made subsequent to successfully
  562                 // connecting.  Errors occurring while attempting to connect are
  563                 // checked in the connection code. An alternative would be to call
  564                 // mysql_ping() - assuming autoreconnect is off. If that fails
  565                 // then we know connection is toast.
  566             case CR_SERVER_GONE_ERROR:
  567             case CR_SERVER_LOST:
  568             case CR_OUT_OF_MEMORY:
  569             case CR_CONNECTION_ERROR:
  570                 DB_LOG_ERROR(db::MYSQL_FATAL_ERROR)
  571                     .arg(what)
  572                     .arg(text_statements_[static_cast<int>(index)])
  573                     .arg(mysql_error(mysql_))
  574                     .arg(mysql_errno(mysql_));
  575 
  576                 // If there's no lost db callback or it returns false,
  577                 // then we're not attempting to recover so we're done.
  578                 if (!invokeDbLostCallback()) {
  579                     isc_throw(db::DbUnrecoverableError,
  580                               "database connectivity cannot be recovered");
  581                 }
  582 
  583                 // We still need to throw so caller can error out of the current
  584                 // processing.
  585                 isc_throw(db::DbOperationError,
  586                           "fatal database errror or connectivity lost");
  587             default:
  588                 // Connection is ok, so it must be an SQL error
  589                 isc_throw(db::DbOperationError, what << " for <"
  590                           << text_statements_[static_cast<int>(index)]
  591                           << ">, reason: "
  592                           << mysql_error(mysql_) << " (error code "
  593                           << mysql_errno(mysql_) << ")");
  594             }
  595         }
  596     }
  597 
  598     /// @brief Prepared statements
  599     ///
  600     /// This field is public, because it is used heavily from MySqlConnection
  601     /// and will be from MySqlHostDataSource.
  602     std::vector<MYSQL_STMT*> statements_;
  603 
  604     /// @brief Raw text of statements
  605     ///
  606     /// This field is public, because it is used heavily from MySqlConnection
  607     /// and will be from MySqlHostDataSource.
  608     std::vector<std::string> text_statements_;
  609 
  610     /// @brief MySQL connection handle
  611     ///
  612     /// This field is public, because it is used heavily from MySqlConnection
  613     /// and will be from MySqlHostDataSource.
  614     MySqlHolder mysql_;
  615 };
  616 
  617 }; // end of isc::db namespace
  618 }; // end of isc namespace
  619 
  620 #endif // MYSQL_CONNECTION_H