//! \file nanodbc.h The entirety of nanodbc can be found within this file and nanodbc.cpp.
//! \mainpage
//!
//! \section toc Table of Contents
//! \li \ref license "License"
//! \li \ref credits "Credits"
//! \li \ref examples "Example Usage"
//! \li \ref nanodbc "Namespace Reference"
//! \li Project Homepage
//!
//! \section license License
//! Copyright (C) 2013 lexicalunit
//!
//! The MIT License
//!
//! Permission is hereby granted, free of charge, to any person obtaining a copy
//! of this software and associated documentation files (the "Software"), to deal
//! in the Software without restriction, including without limitation the rights
//! to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//! copies of the Software, and to permit persons to whom the Software is
//! furnished to do so, subject to the following conditions:
//!
//! The above copyright notice and this permission notice shall be included in
//! all copies or substantial portions of the Software.
//!
//! THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//! IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//! FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//! AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//! LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//! OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//! THE SOFTWARE.
//!
//! \section credits Credits
//! Much of the code in this file was originally derived from TinyODBC.
//! TinyODBC is hosted at http://code.google.com/p/tiodbc/
//! Copyright (C) 2008 SqUe squarious@gmail.com
//! License: The MIT License
//!
//! Transaction support was based on the implementation in SimpleDB: C++ ODBC database API.
//! SimpleDB is hosted at http://simpledb.sourceforge.net
//! Copyright (C) 2006 Eminence Technology Pty Ltd
//! Copyright (C) 2008-2010,2012 Russell Kliese russell@kliese.id.au
//! License: GNU Lesser General Public version 2.1
//!
//! Some improvements and features are based on The Python ODBC Library.
//! The Python ODBC Library is hosted at http://code.google.com/p/pyodbc/
//! License: The MIT License
//!
//! Implementation of column binding inspired by Nick E. Geht's source code posted to on CodeGuru.
//! GSODBC hosted at http://www.codeguru.com/mfc_database/gsodbc.html
//! Copyright (C) 2002 Nick E. Geht
//! License: Perpetual license to reproduce, distribute, adapt, perform, display, and sublicense.
//! See http://www.codeguru.com/submission-guidelines.php for details.
//! \page examples Example Usage
//! \brief Example library usage.
//! \include example.cpp
#ifndef NANODBC_H
#define NANODBC_H
#include
#include
#ifdef NANODBC_USE_BOOST
#define NANODBC_TR1_STD std::
#include
#include
namespace std
{
using namespace boost;
}
#else
// You must explicitly request C++11 support by defining NANODBC_USE_CPP11 at compile time
// , otherwise nanodbc will assume it must use tr1 instead.
#ifndef NANODBC_USE_CPP11
#include
#include
#define NANODBC_TR1_STD std::tr1::
#else
#include
#include
#define NANODBC_TR1_STD std::
#endif
#endif
#ifndef DOXYGEN
namespace detail
{
// Safe Bool idiom from http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Safe_bool#Solution_and_Sample_Code
// Creative Commons Attribution/Share-Alike License: http://creativecommons.org/licenses/by-sa/3.0/
// In C++11 and on we can simply use explicit conversion operators instead of all this boilerplate
class safe_bool_base
{
public:
typedef void (safe_bool_base::*bool_type)() const;
void this_type_does_not_support_comparisons() const {}
protected:
safe_bool_base() {}
safe_bool_base(const safe_bool_base&) {}
safe_bool_base& operator=(const safe_bool_base&) {return *this;}
~safe_bool_base() {}
};
template
class safe_bool : private safe_bool_base
{
// private or protected inheritance is very important here as it triggers the
// access control violation in main.
public:
operator bool_type() const
{
return (static_cast(this))->boolean_test() ? &safe_bool_base::this_type_does_not_support_comparisons : 0;
}
protected:
~safe_bool() {}
};
} // namespace detail
#endif // DOXYGEN
//! \brief The entirety of nanodbc can be found within this one namespace.
//! \todo Implement retrieval of blob data.
//! \todo Implement reflective features for columns, such as type, to enable visitation.
namespace nanodbc
{
// You must explicitly request Unicode support by defining NANODBC_USE_UNICODE at compile time.
#ifndef DOXYGEN
#ifdef NANODBC_USE_UNICODE
typedef std::wstring string_type;
#else
typedef std::string string_type;
#endif // NANODBC_USE_UNICODE
#if defined(_WIN64)
// LLP64 machine, Windows
typedef NANODBC_TR1_STD int64_t null_type;
#elif !defined(_WIN64) && defined(__LP64__)
// LP64 machine, OS X or Linux
typedef long null_type;
#else
// 32-bit machine
typedef long null_type;
#endif
#else
//! string_type will be std::wstring if NANODBC_USE_UNICODE is defined, otherwise std::string.
typedef unspecified-type string_type;
//! null_type will be int64_t for 64-bit compilations, otherwise long.
typedef unspecified-type null_type;
#endif // DOXYGEN
//! \addtogroup exceptions Exception Types
//! \brief Possible error conditions.
//!
//! Specific errors such as type_incompatible_error, null_access_error, and index_range_error can arise
//! from improper use of the nanodbc library. The general database_error is for all other situations
//! in which the ODBC driver or C API reports an error condition. The explanatory string for database_error
//! will, if possible, contain a diagnostic message obtained from SQLGetDiagRec().
//! @{
//! \brief Type incompatible.
//! \see exceptions
class type_incompatible_error : public std::runtime_error
{
public:
type_incompatible_error();
const char* what() const throw();
};
//! \brief Accessed null data.
//! \see exceptions
class null_access_error : public std::runtime_error
{
public:
null_access_error();
const char* what() const throw();
};
//! \brief Index out of range.
//! \see exceptions
class index_range_error : public std::runtime_error
{
public:
index_range_error();
const char* what() const throw();
};
//! \brief Programming logic error.
//! \see exceptions
class programming_error : public std::runtime_error
{
public:
explicit programming_error(const std::string& info);
const char* what() const throw();
};
//! \brief General database error.
//! \see exceptions
class database_error : public std::runtime_error
{
public:
//! \brief Creates a runtime_error with a message describing the last ODBC error generated for the given handle and handle_type.
//! \param handle The native ODBC statement or connection handle.
//! \param handle_type The native ODBC handle type code for the given handle.
//! \param info Additional information that will be appended to the beginning of the error message.
database_error(void* handle, short handle_type, const std::string& info = "");
const char* what() const throw();
};
//! @}
//! \addtogroup utility Utility Classes
//! \brief Additional nanodbc utility classes.
//!
//! \{
//! \brief A type for representing date data.
struct date
{
NANODBC_TR1_STD int16_t year; //!< Year [0-inf).
NANODBC_TR1_STD int16_t month; //!< Month of the year [1-12].
NANODBC_TR1_STD int16_t day; //!< Day of the month [1-31].
};
//! \brief A type for representing timestamp data.
struct timestamp
{
NANODBC_TR1_STD int16_t year; //!< Year [0-inf).
NANODBC_TR1_STD int16_t month; //!< Month of the year [1-12].
NANODBC_TR1_STD int16_t day; //!< Day of the month [1-31].
NANODBC_TR1_STD int16_t hour; //!< Hours since midnight [0-23].
NANODBC_TR1_STD int16_t min; //!< Minutes after the hour [0-59].
NANODBC_TR1_STD int16_t sec; //!< Seconds after the minute.
NANODBC_TR1_STD int32_t fract; //!< Fractional seconds.
};
//! \}
//! \addtogroup main Main Classes
//! \brief Main nanodbc classes.
//!
//! @{
//! \brief A resource for managing transaction commits and rollbacks.
//!
//! \attention You will want to use transactions if you are doing batch operations because it will prevent auto commits from occurring after each individual operation is executed.
class transaction
{
public:
//! \brief Begin a transaction on the given connection object.
//! \post Operations that modify the database must now be committed before taking effect.
//! \throws database_error
explicit transaction(const class connection& conn);
//! Copy constructor.
transaction(const transaction& rhs);
//! Assignment.
transaction& operator=(transaction rhs);
//! Member swap.
void swap(transaction& rhs) throw();
//! \brief If this transaction has not been committed, will will rollback any modifying operations.
~transaction() throw();
//! \brief Marks this transaction for commit.
//! \throws database_error
void commit();
//! \brief Marks this transaction for rollback.
void rollback() throw();
//! Returns the connection object.
class connection& connection();
//! Returns the connection object.
const class connection& connection() const;
//! Returns the connection object.
operator class connection&();
//! Returns the connection object.
operator const class connection&() const;
private:
class transaction_impl;
friend class nanodbc::connection;
private:
NANODBC_TR1_STD shared_ptr impl_;
};
//! \brief Represents a statement on the database.
class statement
{
public:
//! \brief Provides support for retrieving output/return parameters.
//! \see bind_parameter()
enum param_direction
{
PARAM_IN //!< Binding an input parameter.
, PARAM_OUT //!< Binding an output parameter.
, PARAM_INOUT //!< Binding an input/output parameter.
, PARAM_RETURN //!< Binding a return parameter.
};
public:
//! \brief Creates a new un-prepared statement.
//! \see execute(), execute_direct(), open(), prepare()
statement();
//! \brief Constructs a statement object and associates it to the given connection.
//! \param conn The connection to use.
//! \see open(), prepare()
explicit statement(class connection& conn);
//! \brief Constructs and prepares a statement using the given connection and query.
//! \param conn The connection to use.
//! \param query The SQL query statement.
//! \param timeout The number in seconds before query timeout. Default is 0 indicating no timeout.
//! \see execute(), execute_direct(), open(), prepare()
statement(class connection& conn, const string_type& query, long timeout = 0);
//! Copy constructor.
statement(const statement& rhs);
//! Assignment.
statement& operator=(statement rhs);
//! Member swap.
void swap(statement& rhs) throw();
//! \brief Closes the statement.
//! \see close()
~statement() throw();
//! \brief Creates a statement for the given connection.
//! \param conn The connection where the statement will be executed.
//! \throws database_error
void open(class connection& conn);
//! \brief Returns true if connection is open.
bool open() const;
//! \brief Returns true if connected to the database.
bool connected() const;
//! \brief Returns the associated connection object if any.
class connection& connection();
//! \brief Returns the associated connection object if any.
const class connection& connection() const;
//! \brief Returns the native ODBC statement handle.
void* native_statement_handle() const;
//! \brief Closes the statement and frees all associated resources.
void close();
//! \brief Cancels execution of the statement.
//! \throws database_error
void cancel();
//! \brief Opens and prepares the given statement to execute on the given connection.
//! \param conn The connection where the statement will be executed.
//! \param query The SQL query that will be executed.
//! \param timeout The number in seconds before query timeout. Default is 0 indicating no timeout.
//! \see open()
//! \throws database_error
void prepare(class connection& conn, const string_type& query, long timeout = 0);
//! \brief Prepares the given statement to execute its associated connection.
//! If the statement is not open throws programming_error.
//! \param query The SQL query that will be executed.
//! \param timeout The number in seconds before query timeout. Default is 0 indicating no timeout.
//! \see open()
//! \throws database_error, programming_error
void prepare(const string_type& query, long timeout = 0);
//! \brief Sets the number in seconds before query timeout. Default is 0 indicating no timeout.
//! \throws database_error
void timeout(long timeout = 0);
//! \brief Immediately opens, prepares, and executes the given query directly on the given connection.
//! \param conn The connection where the statement will be executed.
//! \param query The SQL query that will be executed.
//! \param batch_operations Numbers of rows to fetch per rowset, or the number of batch parameters to process.
//! \param timeout The number in seconds before query timeout. Default is 0 indicating no timeout.
//! \return A result set object.
//! \attention You will want to use transactions if you are doing batch operations because it will prevent auto commits from occurring after each individual operation is executed.
//! \see open(), prepare(), execute(), result, transaction
class result execute_direct(class connection& conn, const string_type& query, long batch_operations = 1, long timeout = 0);
//! \brief Execute the previously prepared query now.
//! \param batch_operations Numbers of rows to fetch per rowset, or the number of batch parameters to process.
//! \param timeout The number in seconds before query timeout. Default is 0 indicating no timeout.
//! \throws database_error
//! \return A result set object.
//! \attention You will want to use transactions if you are doing batch operations because it will prevent auto commits from occurring after each individual operation is executed.
//! \see open(), prepare(), execute(), result, transaction
class result execute(long batch_operations = 1, long timeout = 0);
//! \brief Returns the number of rows affected by the request or –1 if the number of affected rows is not available.
//! \throws database_error
long affected_rows() const;
//! \brief Returns the number of columns in a result set.
//! \throws database_error
short columns() const;
//! \brief Resets all currently bound parameters.
void reset_parameters() throw();
//! \brief Returns the parameter size for the indicated parameter placeholder within a prepared statement.
unsigned long parameter_size(short param) const;
//! \brief Binds the given value to the given parameter placeholder number in the prepared statement.
//!
//! If your prepared SQL query has any ? placeholders, this is how you bind values to them.
//! Placeholder numbers count from left to right and are 0-indexed.
//!
//! It is possible to use this function for bulk operations.
//!
//! \param param Placeholder position.
//! \param value Value to substitute into placeholder.
//! \param nulls Used to batch insert nulls into the database.
//! \param param_direciton ODBC parameter direction.
//! \throws database_error
template
void bind_parameter(short param, const T* value, null_type* nulls = 0, param_direction direction = PARAM_IN);
//! \brief Binds the given values to the given parameter placeholder number in the prepared statement.
//!
//! If your prepared SQL query has any ? placeholders, this is how you bind values to them.
//! Placeholder numbers count from left to right and are 0-indexed.
//!
//! Typically you would use bulk operations with a row size of N when executing a statement bound this way.
//!
//! \param param Placeholder position.
//! \param values Values to bulk substitute into placeholder.
//! \param nulls Used to batch insert nulls into the database.
//! \param param_direciton ODBC parameter direction.
//! \throws database_error
template
void bind_parameter(short param, const T(*values)[N], null_type* nulls = 0, param_direction direction = PARAM_IN)
{
bind_parameter(param, reinterpret_cast(values), nulls, direction);
}
//! \brief Binds the given string values to the given parameter placeholder number in the prepared statement.
//!
//! If your prepared SQL query has any ? placeholders, this is how you bind values to them.
//! Placeholder numbers count from left to right and are 0-indexed.
//!
//! This function is dedicated to bulk operations involving strings.
//!
//! \param param Placeholder position.
//! \param values Values to bulk substitute into placeholder.
//! \param nulls Used to batch insert nulls into the database.
//! \param param_direciton ODBC parameter direction.
//! \throws database_error
template
void bind_strings(long param, const string_type::value_type (&values)[N][M], null_type* nulls = 0, param_direction direction = PARAM_IN)
{
bind_parameter(param, reinterpret_cast(values), nulls, direction);
}
private:
class statement_impl;
friend class nanodbc::result;
private:
NANODBC_TR1_STD shared_ptr impl_;
};
//! \brief Manages and encapsulates ODBC resources such as the connection and environment handles.
class connection
{
public:
//! \brief Create new connection object, initially not connected.
connection();
//! Copy constructor.
connection(const connection& rhs);
//! Assignment.
connection& operator=(connection rhs);
//! Member swap.
void swap(connection&) throw();
//! \brief Create new connection object and immediately connect to the given data source.
//! \param dsn The name of the data source.
//! \param user The username for authenticating to the data source.
//! \param pass The password for authenticating to the data source.
//! \param timeout The number in seconds before connection timeout. Default is 0 indicating no timeout.
//! \throws database_error
//! \see connected(), connect()
connection(const string_type& dsn, const string_type& user, const string_type& pass, long timeout = 0);
//! \brief Create new connection object and immediately connect using the given connection string.
//! \param connection_string The connection string for establishing a connection.
//! \param timeout The number in seconds before connection timeout. Default is 0 indicating no timeout.
//! \throws database_error
//! \see connected(), connect()
connection(const string_type& connection_string, long timeout = 0);
//! \brief Automatically disconnects from the database and frees all associated resources.
//!
//! Will not throw even if disconnecting causes some kind of error and raises an exception.
//! If you explicitly need to know if disconnect() succeeds, call it directly.
~connection() throw();
//! \brief Create new connection object and immediately connect to the given data source.
//! \param dsn The name of the data source.
//! \param user The username for authenticating to the data source.
//! \param pass The password for authenticating to the data source.
//! \param timeout The number in seconds before connection timeout. Default is 0 indicating no timeout.
//! \throws database_error
//! \see connected()
void connect(const string_type& dsn, const string_type& user, const string_type& pass, long timeout = 0);
//! \brief Create new connection object and immediately connect using the given connection string.
//! \param connection_string The connection string for establishing a connection.
//! \param timeout The number in seconds before connection timeout. Default is 0 indicating no timeout.
//! \throws database_error
//! \see connected()
void connect(const string_type& connection_string, long timeout = 0);
//! \brief Returns true if connected to the database.
bool connected() const;
//! \brief Disconnects from the database, but maintains environment and handle resources.
void disconnect();
//! \brief Returns the number of transactions currently held for this connection.
std::size_t transactions() const;
//! \brief Returns the native ODBC database connection handle.
void* native_dbc_handle() const;
//! \brief Returns the native ODBC environment handle.
void* native_env_handle() const;
//! \brief Returns the name of the ODBC driver.
//! \throws database_error
string_type driver_name() const;
private:
std::size_t ref_transaction();
std::size_t unref_transaction();
bool rollback() const;
void rollback(bool onoff);
private:
class connection_impl;
friend class nanodbc::transaction::transaction_impl;
private:
NANODBC_TR1_STD shared_ptr impl_;
};
#ifndef DOXYGEN
#ifdef NANODBC_USE_CPP11
class result
#else
class result : public detail::safe_bool
#endif
#else
//! \brief A resource for managing result sets from statement execution.
//!
//! \see statement::execute(), statement::execute_direct()
//! \note result objects may be copied, however all copies will refer to the same underlying ODBC result set.
class result
#endif // doxygen
{
public:
//! Empty result set.
result();
//! Free result set.
~result() throw();
//! Copy constructor.
result(const result& rhs);
//! Assignment.
result& operator=(result rhs);
//! Member swap.
void swap(result& rhs) throw();
//! \brief Returns the native ODBC statement handle.
void* native_statement_handle() const;
//! \brief The rowset size for this result set.
long rowset_size() const throw();
//! \brief Returns the number of rows affected by the request or –1 if the number of affected rows is not available.
//! \throws database_error
long affected_rows() const;
//! \brief Returns the number of rows in the current rowset or 0 if the number of rows is not available.
long rows() const throw();
//! \brief Returns the number of columns in a result set.
//! \throws database_error
short columns() const;
//! \brief Fetches the first row in the current result set.
//! \return true if there are more results or false otherwise.
//! \throws database_error
bool first();
//! \brief Fetches the last row in the current result set.
//! \return true if there are more results or false otherwise.
//! \throws database_error
bool last();
//! \brief Fetches the next row in the current result set.
//! \return true if there are more results or false otherwise.
//! \throws database_error
bool next();
//! \brief Fetches the prior row in the current result set.
//! \return true if there are more results or false otherwise.
//! \throws database_error
bool prior();
//! \brief Moves to and fetches the specified row in the current result set.
//! \return true if there are results or false otherwise.
//! \throws database_error
bool move(long row);
//! \brief Skips a number of rows and then fetches the resulting row in the current result set.
//! \return true if there are results or false otherwise.
//! \throws database_error
bool skip(long rows);
//! \brief Returns the row position in the current result set.
unsigned long position() const;
//! \brief Returns true if there are no more results in the current result set.
bool end() const throw();
//! \brief Gets data from the given column of the current rowset.
//!
//! Columns are numbered from left to right and 0-indexed.
//! \param column position.
//! \throws database_error, index_range_error, type_incompatible_error, null_access_error
template
T get(short column) const;
//! \brief Gets data from the given column of the current rowset.
//! If the data is null, fallback is returned instead.
//!
//! Columns are numbered from left to right and 0-indexed.
//! \param column position.
//! \param fallback if value is null, return fallback instead.
//! \throws database_error, index_range_error, type_incompatible_error
template
T get(short column, const T& fallback) const;
//! \brief Gets data from the given column by name of the current rowset.
//!
//! \param column column's name.
//! \param row If there are multiple rows in this rowset, get from the specified row.
//! \throws database_error, index_range_error, type_incompatible_error, null_access_error
template
T get(const string_type& column_name) const;
//! \brief Gets data from the given column by name of the current rowset.
//! If the data is null, fallback is returned instead.
//!
//! \param column_name column's name.
//! \param fallback if value is null, return fallback instead.
//! \throws database_error, index_range_error, type_incompatible_error
template
T get(const string_type& column_name, const T& fallback) const;
//! \brief Returns true if and only if the given column of the current rowset is null.
//!
//! Columns are numbered from left to right and 0-indexed.
//! \param column position.
//! \throws database_error, index_range_error
bool is_null(short column) const;
//! \brief Returns true if and only if the given column by name of the current rowset is null.
//!
//! \param column column's name.
//! \throws database_error, index_range_error
bool is_null(const string_type& column_name) const;
//! \brief Returns the name of the specified column.
//!
//! Columns are numbered from left to right and 0-indexed.
//! \param column position.
//! \throws index_range_error
string_type column_name(short column) const;
//! \brief Returns the size of the specified column.
//!
//! Columns are numbered from left to right and 0-indexed.
//! \param Column position.
//! \throws index_range_error
long column_size(short column) const;
//! \brief Returns the column number of the specified column name.
//!
//! Columns are numbered from left to right and 0-indexed.
//! \param column column's name.
//! \throws index_range_error
short column(const string_type& column_name) const;
//! Returns a identifying integer value representing the C type of this column.
int column_datatype(short column) const;
//! Returns a identifying integer value representing the C type of this column by name.
int column_datatype(const string_type& column_name) const;
//! Returns the next result, for example when stored procedure returns multiple result sets.
bool next_result() const;
#ifndef DOXYGEN
#ifdef NANODBC_USE_CPP11
explicit operator bool() const;
#else
bool boolean_test() const;
#endif // NANODBC_USE_CPP11
#else
//! If and only if result object is valid, returns true.
//! \note A safe-bool idiom is used if NANODBC_USE_CPP11 is not defined, otherwise an explicit conversion operator is used.
operator bool() const;
#endif // DOXYGEN
private:
result(statement statement, long rowset_size);
private:
class result_impl;
friend class nanodbc::statement::statement_impl;
private:
NANODBC_TR1_STD shared_ptr impl_;
};
//! @}
//! \addtogroup main Free Functions
//! \brief Convenience functions.
//!
//! @{
//! \brief Immediately opens, prepares, and executes the given query directly on the given connection.
//! \param conn The connection where the statement will be executed.
//! \param query The SQL query that will be executed.
//! \param batch_operations Numbers of rows to fetch per rowset, or the number of batch parameters to process.
//! \param timeout The number in seconds before query timeout. Default is 0 indicating no timeout.
//! \return A result set object.
//! \attention You will want to use transactions if you are doing batch operations because it will prevent auto commits from occurring after each individual operation is executed.
//! \see open(), prepare(), execute(), result, transaction
result execute(connection& conn, const string_type& query, long batch_operations = 1, long timeout = 0);
//! \brief Execute the previously prepared query now.
//! \param stmt The prepared statement that will be executed.
//! \param batch_operations Numbers of rows to fetch per rowset, or the number of batch parameters to process.
//! \throws database_error
//! \return A result set object.
//! \attention You will want to use transactions if you are doing batch operations because it will prevent auto commits from occurring after each individual operation is executed.
//! \see open(), prepare(), execute(), result
result execute(statement& stmt, long batch_operations = 1);
//! \brief Execute the previously prepared query now.
//! Executes within the context of a transaction object and commits the transaction directly after execution.
//! \param stmt The prepared statement that will be executed in batch.
//! \param batch_operations Numbers of rows to fetch per rowset, or the number of batch parameters to process.
//! \throws database_error
//! \return A result set object.
//! \see open(), prepare(), execute(), result, transaction
result transact(statement& stmt, long batch_operations);
//! \brief Prepares the given statement to execute on it associated connection.
//! If the statement is not open throws programming_error.
//! \param conn The connection where the statement will be executed.
//! \param query The SQL query that will be executed.
//! \param timeout The number in seconds before query timeout. Default is 0 indicating no timeout.
//! \see open()
//! \throws database_error, programming_error
void prepare(statement& stmt, const string_type& query, long timeout = 0);
//! @}
} // namespace nanodbc
#undef NANODBC_TR1_STD
#endif // NANODBC_H