/// \file nanodbc.h The entirety of nanodbc can be found within this file and nanodbc.cpp.
/// \mainpage
///
/// \section synopsis Synopsis
/// This library provides a wrapper API for the native ODBC API. It aims to do everything ODBC does,
/// but with a \b much nicer interface. Anything it doesn't (yet) do can be done by retrieving the
/// native ODBC handles and dropping down to straight ODBC C API code.
/// For more propaganda, please see the project
/// homepage.
///
/// \section toc Table of Contents
/// - \ref license "License"
/// - \ref credits "Credits"
/// - Source level documentation:
/// - \ref nanodbc "nanodbc namespace"
/// - \ref exceptions
/// - \ref utility
/// - \ref mainc
/// - \ref mainf
/// - \ref binding
/// - \ref bind_multi
/// - \ref bind_strings
///
/// \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
///
/// The idea for using RAII for transactions was inspired by SimpleDB: C++ ODBC database API,
/// however the code in nanodbc is original and not derived from SimpleDB. Therefore
/// the LGPL license under which SimpleDB is distributed does NOT apply to nanodbc.
/// 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.
///
#ifndef NANODBC_H
#define NANODBC_H
#include
#include
#include
#include
#include
#include
#include
#ifndef __clang__
#include
#endif
/// \brief The entirety of nanodbc can be found within this one namespace.
///
/// \note This library does not make any exception safety guarantees, but should work just fine with
/// a threading enabled ODBC driver. If you want to use nanodbc objects in threads I recommend
/// each thread keep their own connection to the database. Otherwise you must synchronize any
/// access to nanodbc objects.
namespace nanodbc
{
// clang-format off
// .d8888b. .d888 d8b 888 d8b
// d88P Y88b d88P" Y8P 888 Y8P
// 888 888 888 888
// 888 .d88b. 88888b. 888888 888 .d88b. 888 888 888d888 8888b. 888888 888 .d88b. 88888b.
// 888 d88""88b 888 "88b 888 888 d88P"88b 888 888 888P" "88b 888 888 d88""88b 888 "88b
// 888 888 888 888 888 888 888 888 888 888 888 888 888 .d888888 888 888 888 888 888 888
// Y88b d88P Y88..88P 888 888 888 888 Y88b 888 Y88b 888 888 888 888 Y88b. 888 Y88..88P 888 888
// "Y8888P" "Y88P" 888 888 888 888 "Y88888 "Y88888 888 "Y888888 "Y888 888 "Y88P" 888 888
// 888
// Y8b d88P
// "Y88P"
// MARK: Configuration -
// clang-format on
/// \addtogroup macros Macros
/// \brief Macros that nanodbc uses, can be overriden by users.
///
/// @{
#ifdef DOXYGEN
/// \def NANODBC_ASSERT(expression)
/// \brief Assertion.
///
/// By default, nanodbc uses C \c assert() for internal assertions.
/// User can override it by defining \c NANODBC_ASSERT(expr) macro
/// in the nanodbc.h file and customizing it as desired,
/// before building the library.
///
/// \code{.cpp}
/// #ifdef _DEBUG
/// #include
/// #define NANODBC_ASSERT _ASSERTE
/// #endif
/// \endcode
#define NANODBC_ASSERT(expression) assert(expression)
#endif
/// @}
// You must explicitly request Unicode support by defining NANODBC_USE_UNICODE at compile time.
#ifndef DOXYGEN
#ifdef NANODBC_USE_UNICODE
#ifdef NANODBC_USE_IODBC_WIDE_STRINGS
#define NANODBC_TEXT(s) U##s
typedef std::u32string string_type;
#else
#ifdef _MSC_VER
typedef std::wstring string_type;
#define NANODBC_TEXT(s) L##s
#else
typedef std::u16string string_type;
#define NANODBC_TEXT(s) u##s
#endif
#endif
#else
typedef std::string string_type;
#define NANODBC_TEXT(s) s
#endif
#if defined(_WIN64)
// LLP64 machine: Windows
typedef 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
/// \def NANODBC_TEXT(s)
/// \brief Creates a string literal of the type corresponding to `nanodbc::string_type`.
///
/// By default, the macro maps to an unprefixed string literal.
/// If building with options NANODBC_USE_UNICODE=ON and
/// NANODBC_USE_IODBC_WIDE_STRINGS=ON specified, then it prefixes a literal with U"...".
/// If only NANODBC_USE_UNICODE=ON is specified, then:
/// * If building with Visual Studio, then the macro prefixes a literal with L"...".
/// * Otherwise, it prefixes a literal with u"...".
#define NANODBC_TEXT(s) s
/// \c string_type will be \c std::u16string or \c std::32string if \c NANODBC_USE_UNICODE defined.
///
/// Otherwise it will be \c std::string.
typedef unspecified - type string_type;
/// \c null_type will be \c int64_t for 64-bit compilations, otherwise \c long.
typedef unspecified - type null_type;
#endif
#if defined(_MSC_VER) && _MSC_VER <= 1800
// These versions of Visual C++ do not yet support \c noexcept or \c std::move.
#define NANODBC_NOEXCEPT
#define NANODBC_NO_MOVE_CTOR
#else
#define NANODBC_NOEXCEPT noexcept
#endif
// clang-format off
// 8888888888 888 888 888 888 d8b
// 888 888 888 888 888 Y8P
// 888 888 888 888 888
// 8888888 888d888 888d888 .d88b. 888d888 8888888888 8888b. 88888b. .d88888 888 888 88888b. .d88b.
// 888 888P" 888P" d88""88b 888P" 888 888 "88b 888 "88b d88" 888 888 888 888 "88b d88P"88b
// 888 888 888 888 888 888 888 888 .d888888 888 888 888 888 888 888 888 888 888 888
// 888 888 888 Y88..88P 888 888 888 888 888 888 888 Y88b 888 888 888 888 888 Y88b 888
// 8888888888 888 888 "Y88P" 888 888 888 "Y888888 888 888 "Y88888 888 888 888 888 "Y88888
// 888
// Y8b d88P
// "Y88P"
// MARK: Error Handling -
// clang-format on
/// \addtogroup exceptions Exception types
/// \brief Possible error conditions.
///
/// Specific errors such as \c type_incompatible_error, \c null_access_error, and
/// \c index_range_error can arise from improper use of the nanodbc library. The general
/// \c 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 \c SQLGetDiagRec().
/// @{
/// \brief Type incompatible.
/// \see exceptions
class type_incompatible_error : public std::runtime_error
{
public:
type_incompatible_error();
const char* what() const NANODBC_NOEXCEPT;
};
/// \brief Accessed null data.
/// \see exceptions
class null_access_error : public std::runtime_error
{
public:
null_access_error();
const char* what() const NANODBC_NOEXCEPT;
};
/// \brief Index out of range.
/// \see exceptions
class index_range_error : public std::runtime_error
{
public:
index_range_error();
const char* what() const NANODBC_NOEXCEPT;
};
/// \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 NANODBC_NOEXCEPT;
};
/// \brief General database error.
/// \see exceptions
class database_error : public std::runtime_error
{
public:
/// \brief Creates runtime_error with message about last ODBC error.
/// \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 info 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 NANODBC_NOEXCEPT;
long native() const NANODBC_NOEXCEPT;
const std::string state() const NANODBC_NOEXCEPT;
private:
long native_error;
std::string sql_state;
std::string message;
};
/// @}
// clang-format off
// 888 888 888 d8b 888 d8b 888 d8b
// 888 888 888 Y8P 888 Y8P 888 Y8P
// 888 888 888 888 888
// 888 888 888888 888 888 888 888888 888 .d88b. .d8888b
// 888 888 888 888 888 888 888 888 d8P Y8b 88K
// 888 888 888 888 888 888 888 888 88888888 "Y8888b.
// Y88b. .d88P Y88b. 888 888 888 Y88b. 888 Y8b. X88
// "Y88888P" "Y888 888 888 888 "Y888 888 "Y8888 88888P'
// MARK: Utilities -
// clang-format on
/// \addtogroup utility Utilities
/// \brief Additional nanodbc utility classes and functions.
///
/// \{
/// \brief A type for representing date data.
struct date
{
std::int16_t year; ///< Year [0-inf).
std::int16_t month; ///< Month of the year [1-12].
std::int16_t day; ///< Day of the month [1-31].
};
/// \brief A type for representing time data.
struct time
{
std::int16_t hour; ///< Hours since midnight [0-23].
std::int16_t min; ///< Minutes after the hour [0-59].
std::int16_t sec; ///< Seconds after the minute.
};
/// \brief A type for representing timestamp data.
struct timestamp
{
std::int16_t year; ///< Year [0-inf).
std::int16_t month; ///< Month of the year [1-12].
std::int16_t day; ///< Day of the month [1-31].
std::int16_t hour; ///< Hours since midnight [0-23].
std::int16_t min; ///< Minutes after the hour [0-59].
std::int16_t sec; ///< Seconds after the minute.
std::int32_t fract; ///< Fractional seconds.
};
/// \}
/// \addtogroup mainc Main classes
/// \brief Main nanodbc classes.
///
/// @{
// clang-format off
// 88888888888 888 d8b
// 888 888 Y8P
// 888 888
// 888 888d888 8888b. 88888b. .d8888b 8888b. .d8888b 888888 888 .d88b. 88888b.
// 888 888P" "88b 888 "88b 88K "88b d88P" 888 888 d88""88b 888 "88b
// 888 888 .d888888 888 888 "Y8888b. .d888888 888 888 888 888 888 888 888
// 888 888 888 888 888 888 X88 888 888 Y88b. Y88b. 888 Y88..88P 888 888
// 888 888 "Y888888 888 888 88888P' "Y888888 "Y8888P "Y888 888 "Y88P" 888 888
// MARK: Transaction -
// clang-format on
/// \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);
#ifndef NANODBC_NO_MOVE_CTOR
/// Move constructor.
transaction(transaction&& rhs) NANODBC_NOEXCEPT;
#endif
/// Assignment.
transaction& operator=(transaction rhs);
/// Member swap.
void swap(transaction& rhs) NANODBC_NOEXCEPT;
/// \brief If this transaction has not been committed, will will rollback any modifying ops.
~transaction() NANODBC_NOEXCEPT;
/// \brief Commits transaction immediately.
/// \throws database_error
void commit();
/// \brief Marks this transaction for rollback.
void rollback() NANODBC_NOEXCEPT;
/// 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:
std::shared_ptr impl_;
};
// clang-format off
// .d8888b. 888 888 888
// d88P Y88b 888 888 888
// Y88b. 888 888 888
// "Y888b. 888888 8888b. 888888 .d88b. 88888b.d88b. .d88b. 88888b. 888888
// "Y88b. 888 "88b 888 d8P Y8b 888 "888 "88b d8P Y8b 888 "88b 888
// "888 888 .d888888 888 88888888 888 888 888 88888888 888 888 888
// Y88b d88P Y88b. 888 888 Y88b. Y8b. 888 888 888 Y8b. 888 888 Y88b.
// "Y8888P" "Y888 "Y888888 "Y888 "Y8888 888 888 888 "Y8888 888 888 "Y888
// MARK: Statement -
// clang-format on
/// \brief Represents a statement on the database.
class statement
{
public:
/// \brief Provides support for retrieving output/return parameters.
/// \see binding
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(), just_execute(), execute_direct(), just_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: 0 meaning no timeout.
/// \see execute(), just_execute(), execute_direct(), just_execute_direct(), open(), prepare()
statement(class connection& conn, const string_type& query, long timeout = 0);
/// \brief Copy constructor.
statement(const statement& rhs);
#ifndef NANODBC_NO_MOVE_CTOR
/// \brief Move constructor.
statement(statement&& rhs) NANODBC_NOEXCEPT;
#endif
/// \brief Assignment.
statement& operator=(statement rhs);
/// \brief Member swap.
void swap(statement& rhs) NANODBC_NOEXCEPT;
/// \brief Closes the statement.
/// \see close()
~statement() NANODBC_NOEXCEPT;
/// \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 0 meaning 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.
/// \note 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 0 meaning 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 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 0 meaning 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 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);
#if !defined(NANODBC_DISABLE_ASYNC)
/// \brief Prepare the given statement, in asynchronous mode.
/// \note If the statement is not open throws programming_error.
///
/// This method will only be available if nanodbc is built against ODBC headers and library that
/// supports asynchronous mode. Such that the identifiers `SQL_ATTR_ASYNC_STMT_EVENT` and
/// `SQLCompleteAsync` are extant. Otherwise this method will be defined, but not implemented.
///
/// Asynchronous features can be disabled entirely by defining `NANODBC_DISABLE_ASYNC` when
/// building nanodbc.
///
/// \param event_handle The event handle the caller will wait before calling complete_prepare.
/// \param query The SQL query that will be prepared.
/// \param timeout The number in seconds before query timeout. Default 0 meaning no timeout.
/// \throws database_error
/// \return Boolean: true if the event handle needs to be awaited, false is result is ready now.
/// \see complete_prepare()
bool async_prepare(const string_type& query, void* event_handle, long timeout = 0);
/// \brief Completes a previously initiated asynchronous query preparation.
///
/// This method will only be available if nanodbc is built against ODBC headers and library that
/// supports asynchronous mode. Such that the identifiers `SQL_ATTR_ASYNC_STMT_EVENT` and
/// `SQLCompleteAsync` are extant. Otherwise this method will be defined, but not implemented.
///
/// Asynchronous features can be disabled entirely by defining `NANODBC_DISABLE_ASYNC` when
/// building nanodbc.
///
/// \throws database_error
/// \see async_prepare()
void complete_prepare();
/// \brief Opens, prepares, and executes query directly on the given connection, in async mode.
///
/// This method will only be available if nanodbc is built against ODBC headers and library that
/// supports asynchronous mode. Such that the identifiers `SQL_ATTR_ASYNC_STMT_EVENT` and
/// `SQLCompleteAsync` are extant. Otherwise this method will be defined, but not implemented.
///
/// Asynchronous features can be disabled entirely by defining `NANODBC_DISABLE_ASYNC` when
/// building nanodbc.
///
/// \param conn The connection where the statement will be executed.
/// \param event_handle The event handle the caller will wait before calling complete_execute.
/// \param query The SQL query that will be executed.
/// \param batch_operations Rows to fetch per rowset or number of batch parameters to process.
/// \param timeout The number in seconds before query timeout. Default 0 meaning no timeout.
/// \throws database_error
/// \return Boolean: true if event handle needs to be awaited, false if result ready now.
/// \attention You will want to use transactions if you are doing batch operations because it
/// will prevent auto commits after each individual operation is executed.
/// \see complete_execute(), open(), prepare(), execute(), result, transaction
bool async_execute_direct(
class connection& conn,
void* event_handle,
const string_type& query,
long batch_operations = 1,
long timeout = 0);
/// \brief Execute the previously prepared query now, in asynchronous mode.
///
/// This method will only be available if nanodbc is built against ODBC headers and library that
/// supports asynchronous mode. Such that the identifiers `SQL_ATTR_ASYNC_STMT_EVENT` and
/// `SQLCompleteAsync` are extant. Otherwise this method will be defined, but not implemented.
///
/// Asynchronous features can be disabled entirely by defining `NANODBC_DISABLE_ASYNC` when
/// building nanodbc.
///
/// \param event_handle The event handle the caller will wait before calling complete_execute.
/// \param batch_operations Rows to fetch per rowset or number of batch parameters to process.
/// \param timeout The number in seconds before query timeout. Default 0 meaning no timeout.
/// \throws database_error
/// \return Boolean: true if event handle needs to be awaited, false if result is ready now.
/// \attention You will want to use transactions if you are doing batch operations because it
/// will prevent auto commits after each individual operation is executed.
/// \see complete_execute(), open(), prepare(), result, transaction
bool async_execute(void* event_handle, long batch_operations = 1, long timeout = 0);
/// \brief Completes a previously initiated asynchronous query execution, returning the result.
///
/// This method will only be available if nanodbc is built against ODBC headers and library that
/// supports asynchronous mode. Such that the identifiers `SQL_ATTR_ASYNC_STMT_EVENT` and
/// `SQLCompleteAsync` are extant. Otherwise this method will be defined, but not implemented.
///
/// Asynchronous features can be disabled entirely by defining `NANODBC_DISABLE_ASYNC` when
/// building nanodbc.
///
/// \throws database_error
/// \return A result set object.
/// \param batch_operations Rows to fetch per rowset or number of batch parameters to process.
/// \see async_execute(), async_execute_direct()
class result complete_execute(long batch_operations = 1);
/// left for backwards compatibility
class result async_complete(long batch_operations = 1);
/// undocumented - for internal use only (used from result_impl)
void enable_async(void* event_handle);
/// undocumented - for internal use only (used from result_impl)
void disable_async() const;
#endif
/// \brief Execute the previously prepared query now without constructing result object.
/// \param conn The connection where the statement will be executed.
/// \param query The SQL query that will be executed.
/// \param batch_operations Rows to fetch per rowset, or number of batch parameters to process.
/// \param timeout 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 after each individual operation is executed.
/// \see open(), prepare(), execute(), execute_direct(), result, transaction
void just_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 Rows to fetch per rowset, or number of batch parameters to process.
/// \param timeout The number in seconds before query timeout. Default 0 meaning 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 after each individual operation is executed.
/// \see open(), prepare(), result, transaction
class result execute(long batch_operations = 1, long timeout = 0);
/// \brief Execute the previously prepared query now without constructing result object.
/// \param batch_operations Rows to fetch per rowset, or number of batch parameters to process.
/// \param timeout The number in seconds before query timeout. Default 0 meaning 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 after each individual operation is executed.
/// \see open(), prepare(), execute(), result, transaction
void just_execute(long batch_operations = 1, long timeout = 0);
/// \brief Returns the input and output paramters of the specified stored procedure.
/// \param catalog The catalog name of the procedure.
/// \param schema Pattern to use for schema names.
/// \param procedure The name of the procedure.
/// \param column Pattern to use for column names.
/// \throws database_error
/// \return A result set object.
class result procedure_columns(
const string_type& catalog,
const string_type& schema,
const string_type& procedure,
const string_type& column);
/// \brief Returns rows affected by the request or -1 if 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() NANODBC_NOEXCEPT;
/// \brief Returns the number of parameters in the statement.
/// \throws database_error
short parameters() const;
/// \brief Returns parameter size for indicated parameter placeholder in a prepared statement.
unsigned long parameter_size(short param_index) const;
/// \addtogroup binding Binding parameters
/// \brief These functions are used to bind values to ODBC parameters.
///
/// @{
/// \brief Binds given value to 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 NOT possible to use these functions for batch operations as number of elements is not
/// specified here.
///
/// \param param_index Zero-based index of parameter marker (placeholder position).
/// \param value Value to substitute into placeholder.
/// \param direction ODBC parameter direction.
/// \throws database_error
template
void bind(short param_index, T const* value, param_direction direction = PARAM_IN);
/// \addtogroup bind_multi Binding multiple non-string values
/// \brief Binds given values to given parameter placeholder number in the prepared statement.
///
/// If your prepared SQL query has any parameter markers, ? (question mark) placeholders,
/// this is how you bind values to them.
/// Parameter markers are numbered using Zero-based index from left to right.
///
/// It is possible to use these functions for batch operations.
///
/// \param param_index Zero-based index of parameter marker (placeholder position).
/// \param values Values to substitute into placeholder.
/// \param batch_size The number of values being bound.
/// \param null_sentry Value which should represent a null value.
/// \param nulls Flags for values that should be set to a null value.
/// \param param_direciton ODBC parameter direction.
/// \throws database_error
///
/// @{
/// \brief Binds multiple values.
/// \see bind_multi
template
void bind(
short param_index,
T const* values,
std::size_t batch_size,
param_direction direction = PARAM_IN);
/// \brief Binds multiple values.
/// \see bind_multi
template
void bind(
short param_index,
T const* values,
std::size_t batch_size,
T const* null_sentry,
param_direction direction = PARAM_IN);
/// \brief Binds multiple values.
/// \see bind_multi
template
void bind(
short param_index,
T const* values,
std::size_t batch_size,
bool const* nulls,
param_direction direction = PARAM_IN);
/// \brief Binds multiple values.
/// \see bind_multi
void bind(
short param_index,
std::vector> const& values,
param_direction direction = PARAM_IN);
/// \brief Binds multiple values.
/// \see bind_multi
void bind(
short param_index,
std::vector> const& values,
bool const* nulls,
param_direction direction = PARAM_IN);
/// \brief Binds multiple values.
/// \see bind_multi
void bind(
short param_index,
std::vector> const& values,
uint8_t const* null_sentry,
param_direction direction = PARAM_IN);
/// @}
/// \addtogroup bind_strings Binding multiple string values
/// \brief Binds given string values to parameter marker in prepared statement.
///
/// If your prepared SQL query has any parameter markers, ? (question mark) placeholders,
/// this is how you bind values to them.
/// Parameter markers are numbered using Zero-based index from left to right.
///
/// It is possible to use these functions for batch operations.
///
/// \param param_index Zero-based index of parameter marker (placeholder position).
/// \param values Array of values to substitute into parameter placeholders.
/// \param value_size Maximum length of string value in array.
/// \param batch_size Number of string values to bind. Otherwise template parameter BatchSize is
/// taken as the number of values.
/// \param null_sentry Value which should represent a null value.
/// \param nulls Flags for values that should be set to a null value.
/// \param param_direciton ODBC parameter direction.
/// \throws database_error
///
/// @{
/// \brief Binds multiple string values.
/// \see bind_strings
void bind_strings(
short param_index,
string_type::value_type const* values,
std::size_t value_size,
std::size_t batch_size,
param_direction direction = PARAM_IN);
/// \brief Binds multiple string values.
///
/// Size of the values vector indicates number of values to bind.
/// Longest string in the array determines maximum length of individual value.
///
/// \see bind_strings
void bind_strings(
short param_index,
std::vector const& values,
param_direction direction = PARAM_IN);
/// \brief Binds multiple string values.
/// \see bind_strings
template
void bind_strings(
short param_index,
string_type::value_type const (&values)[BatchSize][ValueSize],
param_direction direction = PARAM_IN)
{
auto param_values = reinterpret_cast(values);
bind_strings(param_index, param_values, ValueSize, BatchSize, direction);
}
/// \brief Binds multiple string values.
/// \see bind_strings
void bind_strings(
short param_index,
string_type::value_type const* values,
std::size_t value_size,
std::size_t batch_size,
string_type::value_type const* null_sentry,
param_direction direction = PARAM_IN);
/// \brief Binds multiple string values.
/// \see bind_strings
void bind_strings(
short param_index,
std::vector const& values,
string_type::value_type const* null_sentry,
param_direction direction = PARAM_IN);
/// \brief Binds multiple string values.
/// \see bind_strings
template
void bind_strings(
short param_index,
string_type::value_type const (&values)[BatchSize][ValueSize],
string_type::value_type const* null_sentry,
param_direction direction = PARAM_IN)
{
auto param_values = reinterpret_cast(values);
bind_strings(param_index, param_values, ValueSize, BatchSize, null_sentry, direction);
}
/// \brief Binds multiple string values.
/// \see bind_strings
void bind_strings(
short param_index,
string_type::value_type const* values,
std::size_t value_size,
std::size_t batch_size,
bool const* nulls,
param_direction direction = PARAM_IN);
/// \brief Binds multiple string values.
/// \see bind_strings
void bind_strings(
short param_index,
std::vector const& values,
bool const* nulls,
param_direction direction = PARAM_IN);
/// \brief Binds multiple string values.
/// \see bind_strings
template
void bind_strings(
short param_index,
string_type::value_type const (&values)[BatchSize][ValueSize],
bool const* nulls,
param_direction direction = PARAM_IN)
{
auto param_values = reinterpret_cast(values);
bind_strings(param_index, param_values, ValueSize, BatchSize, nulls, direction);
}
/// @}
/// \brief Binds null values to the parameter placeholder number in the prepared statement.
///
/// If your prepared SQL query has any parameter markers, ? (question mark) placeholders,
/// this is how you bind values to them.
/// Parameter markers are numbered using Zero-based index from left to right.
///
/// It is possible to use this function for batch operations.
///
/// \param param_index Zero-based index of parameter marker (placeholder position).
/// \param batch_size The number of elements being bound.
/// \throws database_error
void bind_null(short param_index, std::size_t batch_size = 1);
/// @}
private:
typedef std::function null_predicate_type;
private:
class statement_impl;
friend class nanodbc::result;
private:
std::shared_ptr impl_;
};
// clang-format off
// .d8888b. 888 d8b
// d88P Y88b 888 Y8P
// 888 888 888
// 888 .d88b. 88888b. 88888b. .d88b. .d8888b 888888 888 .d88b. 88888b.
// 888 d88""88b 888 "88b 888 "88b d8P Y8b d88P" 888 888 d88""88b 888 "88b
// 888 888 888 888 888 888 888 888 88888888 888 888 888 888 888 888 888
// Y88b d88P Y88..88P 888 888 888 888 Y8b. Y88b. Y88b. 888 Y88..88P 888 888
// "Y8888P" "Y88P" 888 888 888 888 "Y8888 "Y8888P "Y888 888 "Y88P" 888 888
// MARK: Connection -
// clang-format on
/// \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);
#ifndef NANODBC_NO_MOVE_CTOR
/// Move constructor.
connection(connection&& rhs) NANODBC_NOEXCEPT;
#endif
/// Assignment.
connection& operator=(connection rhs);
/// Member swap.
void swap(connection&) NANODBC_NOEXCEPT;
/// \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 Seconds before connection timeout. Default 0 meaning 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 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() NANODBC_NOEXCEPT;
/// \brief 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 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 Connect using the given connection string.
/// \param connection_string The connection string for establishing a connection.
/// \param timeout 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);
#if !defined(NANODBC_DISABLE_ASYNC)
/// \brief Initiate an asynchronous connection operation to the given data source.
///
/// This method will only be available if nanodbc is built against ODBC headers and library that
/// supports asynchronous mode. Such that the identifiers `SQL_ATTR_ASYNC_DBC_EVENT` and
/// `SQLCompleteAsync` are extant. Otherwise this method will be defined, but not implemented.
///
/// Asynchronous features can be disabled entierly by defining `NANODBC_DISABLE_ASYNC` when
/// building nanodbc.
///
/// \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 event_handle The event handle the caller will wait before calling async_complete.
/// \param timeout Seconds before connection timeout. Default is 0 indicating no timeout.
/// \throws database_error
/// \return Boolean: true if event handle needs to be awaited, false if connection is ready now.
/// \see connected()
bool async_connect(
const string_type& dsn,
const string_type& user,
const string_type& pass,
void* event_handle,
long timeout = 0);
/// \brief Initiate an asynchronous connection operation using the given connection string.
///
/// This method will only be available if nanodbc is built against ODBC headers and library that
/// supports asynchronous mode. Such that the identifiers `SQL_ATTR_ASYNC_DBC_EVENT` and
/// `SQLCompleteAsync` are extant. Otherwise this method will be defined, but not implemented.
///
/// Asynchronous features can be disabled entierly by defining `NANODBC_DISABLE_ASYNC` when
/// building nanodbc.
///
/// \param connection_string The connection string for establishing a connection.
/// \param event_handle Event handle the caller will wait before calling async_complete.
/// \param timeout Seconds before connection timeout. Default is 0 indicating no timeout.
/// \throws database_error
/// \return Boolean: true if event handle needs to be awaited, false if connection is ready now.
/// \see connected()
bool async_connect(const string_type& connection_string, void* event_handle, long timeout = 0);
/// \brief Completes a previously initiated asynchronous connection operation.
///
/// Asynchronous features can be disabled entierly by defining `NANODBC_DISABLE_ASYNC` when
/// building nanodbc.
void async_complete();
#endif
/// \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 information from the ODBC connection as a string.
template
T get_info(short info_type) const;
/// \brief Returns name of the DBMS product.
/// Returns the ODBC information type SQL_DBMS_NAME of the DBMS product
/// accesssed by the driver via the current connection.
string_type dbms_name() const;
/// \brief Returns version of the DBMS product.
/// Returns the ODBC information type SQL_DBMS_VER of the DBMS product
/// accesssed by the driver via the current connection.
string_type dbms_version() const;
/// \brief Returns the name of the ODBC driver.
/// \throws database_error
string_type driver_name() const;
/// \brief Returns the name of the currently connected database.
/// Returns the current SQL_DATABASE_NAME information value associated with the connection.
string_type database_name() const;
/// \brief Returns the name of the current catalog.
/// Returns the current setting of the connection attribute SQL_ATTR_CURRENT_CATALOG.
string_type catalog_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:
std::shared_ptr impl_;
};
// clang-format off
// 8888888b. 888 888
// 888 Y88b 888 888
// 888 888 888 888
// 888 d88P .d88b. .d8888b 888 888 888 888888
// 8888888P" d8P Y8b 88K 888 888 888 888
// 888 T88b 88888888 "Y8888b. 888 888 888 888
// 888 T88b Y8b. X88 Y88b 888 888 Y88b.
// 888 T88b "Y8888 88888P' "Y88888 888 "Y888
// MARK: Result -
// clang-format on
class catalog;
/// \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 result set.
class result
{
public:
/// \brief Empty result set.
result();
/// \brief Free result set.
~result() NANODBC_NOEXCEPT;
/// \brief Copy constructor.
result(const result& rhs);
#ifndef NANODBC_NO_MOVE_CTOR
/// \brief Move constructor.
result(result&& rhs) NANODBC_NOEXCEPT;
#endif
/// \brief Assignment.
result& operator=(result rhs);
/// \brief Member swap.
void swap(result& rhs) NANODBC_NOEXCEPT;
/// \brief Returns the native ODBC statement handle.
void* native_statement_handle() const;
/// \brief The rowset size for this result set.
long rowset_size() const NANODBC_NOEXCEPT;
/// \brief Number of affected rows by the request or -1 if the affected rows is not available.
/// \throws database_error
long affected_rows() const;
/// \brief Rows in the current rowset or 0 if the number of rows is not available.
long rows() const NANODBC_NOEXCEPT;
/// \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();
#if !defined(NANODBC_DISABLE_ASYNC)
/// \brief Initiates an asynchronous fetch of the next row in the current result set.
/// \return true if the caller needs to wait for the event to be signalled, false if
/// complete_next() can be called immediately.
/// \throws database_error
bool async_next(void* event_handle);
/// \brief Completes a previously-initiated async fetch for next row in the current result set.
/// \return true if there are more results or false otherwise.
/// \throws database_error
bool complete_next();
#endif
/// \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 at_end() const NANODBC_NOEXCEPT;
/// \brief Gets data from the given column of the current rowset.
///
/// Columns are numbered from left to right and 0-indexed.
/// \param column position.
/// \param result The column's value will be written to this parameter.
/// \throws database_error, index_range_error, type_incompatible_error, null_access_error
template
void get_ref(short column, T& result) 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.
/// \param result The column's value will be written to this parameter.
/// \throws database_error, index_range_error, type_incompatible_error
template
void get_ref(short column, const T& fallback, T& result) const;
/// \brief Gets data from the given column by name of the current rowset.
///
/// \param column_name column's name.
/// \param result The column's value will be written to this parameter.
/// \throws database_error, index_range_error, type_incompatible_error, null_access_error
template
void get_ref(const string_type& column_name, T& result) 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.
/// \param result The column's value will be written to this parameter.
/// \throws database_error, index_range_error, type_incompatible_error
template
void get_ref(const string_type& column_name, const T& fallback, T& result) const;
/// \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_name column's name.
/// \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.
///
/// There is a bug/limitation in ODBC drivers for SQL Server (and possibly others)
/// which causes SQLBindCol() to never write SQL_NOT_NULL to the length/indicator
/// buffer unless you also bind the data column. nanodbc's is_null() will return
/// correct values for (n)varchar(max) columns when you ensure that SQLGetData()
/// has been called for that column (i.e. after get() or get_ref() is called).
///
/// Columns are numbered from left to right and 0-indexed.
/// \see get(), get_ref()
/// \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.
///
/// See is_null(short column) for details on a bug/limitation of some ODBC drivers.
/// \see is_null()
/// \param column_name column's name.
/// \throws database_error, index_range_error
bool is_null(const string_type& column_name) const;
/// \brief Returns the column number of the specified column name.
///
/// Columns are numbered from left to right and 0-indexed.
/// \param column_name column's name.
/// \throws index_range_error
short column(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 size of the specified column by name.
long column_size(const string_type& column_name) const;
/// \brief Returns the number of decimal digits of the specified column.
///
/// Applies to exact numeric types (scale), datetime and interval types (prcision).
/// If the number cannot be determined or is not applicable, drivers typically return 0.
///
/// Columns are numbered from left to right and 0-indexed.
/// \param column position.
/// \throws index_range_error
int column_decimal_digits(short column) const;
/// \brief Returns the number of decimal digits of the specified column by name.
int column_decimal_digits(const string_type& column_name) const;
/// \brief Returns a identifying integer value representing the SQL type of this column.
int column_datatype(short column) const;
/// \brief Returns a identifying integer value representing the SQL type of this column by name.
int column_datatype(const string_type& column_name) const;
/// \brief Returns a identifying integer value representing the C type of this column.
int column_c_datatype(short column) const;
/// \brief Returns a identifying integer value representing the C type of this column by name.
int column_c_datatype(const string_type& column_name) const;
/// \brief Returns the next result, e.g. when stored procedure returns multiple result sets.
bool next_result();
/// \brief If and only if result object is valid, returns true.
explicit operator bool() const;
private:
result(statement statement, long rowset_size);
private:
class result_impl;
friend class nanodbc::statement::statement_impl;
friend class nanodbc::catalog;
private:
std::shared_ptr impl_;
};
/// \brief Single pass input iterator that accesses successive rows in the attached result set.
class result_iterator
{
public:
typedef std::input_iterator_tag iterator_category; ///< Category of iterator.
typedef result value_type; ///< Values returned by iterator access.
typedef result* pointer; ///< Pointer to iteration values.
typedef result& reference; ///< Reference to iteration values.
typedef std::ptrdiff_t difference_type; ///< Iterator difference.
/// Default iterator; an empty result set.
result_iterator() = default;
/// Create result iterator for a given result set.
result_iterator(result& r)
: result_(r)
{
++(*this);
}
/// Dereference.
reference operator*() { return result_; }
/// Access through dereference.
pointer operator->()
{
if (!result_)
throw std::runtime_error("result is empty");
return &(operator*());
}
/// Iteration.
result_iterator& operator++()
{
try
{
if (!result_.next())
result_ = result();
}
catch (...)
{
result_ = result();
}
return *this;
}
/// Iteration.
result_iterator operator++(int)
{
result_iterator tmp(*this);
++(*this);
return tmp;
}
/// Iterators are equal if they a tied to the same native statemnt handle, or both empty.
bool operator==(result_iterator const& rhs) const
{
if (result_ && rhs.result_)
return result_.native_statement_handle() == rhs.result_.native_statement_handle();
else
return !result_ && !rhs.result_;
}
/// Iterators are not equal if they have different native statemnt handles.
bool operator!=(result_iterator const& rhs) const { return !(*this == rhs); }
private:
result result_;
};
/// \brief Returns an iterator to the beginning of the given result set.
inline result_iterator begin(result& r)
{
return result_iterator(r);
}
/// \brief Returns an iterator to the end of a result set.
///
/// The default-constructed `nanodbc::result_iterator` is known as the end-of-result iterator.
/// When a valid `nanodbc::result_iterator` reaches the end of the underlying result set,
/// it becomes equal to the end-of-result iterator.
/// Dereferencing or incrementing it further is undefined.
inline result_iterator end(result& /*r*/)
{
return result_iterator();
}
// clang-format off
//
// .d8888b. 888 888
// d88P Y88b 888 888
// 888 888 888 888
// 888 8888b. 888888 8888b. 888 .d88b. .d88b.
// 888 "88b 888 "88b 888 d88""88b d88P"88b
// 888 888 .d888888 888 .d888888 888 888 888 888 888
// Y88b d88P 888 888 Y88b. 888 888 888 Y88..88P Y88b 888
// "Y8888P" "Y888888 "Y888 "Y888888 888 "Y88P" "Y88888
// 888
// Y8b d88P
// "Y88P"
// MARK: Catalog -
// clang-format on
/// \brief A resource for get catalog information from connected data source.
///
/// Queries are performed using the Catalog Functions in ODBC.
/// All provided operations are convenient wrappers around the ODBC API
/// The original ODBC behaviour should not be affected by any added processing.
class catalog
{
public:
/// \brief Result set for a list of tables in the data source.
class tables
{
public:
bool next(); ///< Move to the next result in the result set.
string_type table_catalog() const; ///< Fetch table catalog.
string_type table_schema() const; ///< Fetch table schema.
string_type table_name() const; ///< Fetch table name.
string_type table_type() const; ///< Fetch table type.
string_type table_remarks() const; ///< Fetch table remarks.
private:
friend class nanodbc::catalog;
tables(result& find_result);
result result_;
};
/// \brief Result set for a list of columns in one or more tables.
class columns
{
public:
bool next(); ///< Move to the next result in the result set.
string_type table_catalog() const; ///< Fetch table catalog.
string_type table_schema() const; ///< Fetch table schema.
string_type table_name() const; ///< Fetch table name.
string_type column_name() const; ///< Fetch column name.
short data_type() const; ///< Fetch column data type.
string_type type_name() const; ///< Fetch column type name.
long column_size() const; ///< Fetch column size.
long buffer_length() const; ///< Fetch buffer length.
short decimal_digits() const; ///< Fetch decimal digits.
short numeric_precision_radix() const; ///< Fetch numeric precission.
short nullable() const; ///< True iff column is nullable.
string_type remarks() const; ///< Fetch column remarks.
string_type column_default() const; ///< Fetch column's default.
short sql_data_type() const; ///< Fetch column's SQL data type.
short sql_datetime_subtype() const; ///< Fetch datetime subtype of column.
long char_octet_length() const; ///< Fetch char octet length.
/// \brief Ordinal position of the column in the table.
/// The first column in the table is number 1.
/// Returns ORDINAL_POSITION column value in result set returned by SQLColumns.
long ordinal_position() const;
/// \brief Fetch column is-nullable information.
///
/// \note MSDN: This column returns a zero-length string if nullability is unknown.
/// ISO rules are followed to determine nullability.
/// An ISO SQL-compliant DBMS cannot return an empty string.
string_type is_nullable() const;
private:
friend class nanodbc::catalog;
columns(result& find_result);
result result_;
};
/// \brief Result set for a list of columns that compose the primary key of a single table.
class primary_keys
{
public:
bool next(); ///< Move to the next result in the result set.
string_type table_catalog() const; ///< Fetch table catalog.
string_type table_schema() const; ///< Fetch table schema.
string_type table_name() const; ///< Fetch table name.
string_type column_name() const; ///< Fetch column name.
/// \brief Column sequence number in the key (starting with 1).
/// Returns valye of KEY_SEQ column in result set returned by SQLPrimaryKeys.
short column_number() const;
/// \brief Primary key name.
/// NULL if not applicable to the data source.
/// Returns valye of PK_NAME column in result set returned by SQLPrimaryKeys.
string_type primary_key_name() const;
private:
friend class nanodbc::catalog;
primary_keys(result& find_result);
result result_;
};
/// \brief Result set for a list of tables and the privileges associated with each table.
class table_privileges
{
public:
bool next(); ///< Move to the next result in the result set
string_type table_catalog() const; ///< Fetch table catalog.
string_type table_schema() const; ///< Fetch table schema.
string_type table_name() const; ///< Fetch table name.
string_type grantor() const; ///< Fetch name of user who granted the privilege.
string_type grantee() const; ///< Fetch name of user whom the privilege was granted.
string_type privilege() const; ///< Fetch the table privilege.
/// Fetch indicator whether the grantee is permitted to grant the privilege to other users.
string_type is_grantable() const;
private:
friend class nanodbc::catalog;
table_privileges(result& find_result);
result result_;
};
/// \brief Creates catalog operating on database accessible through the specified connection.
catalog(connection& conn);
/// \brief Creates result set with catalogs, schemas, tables, or table types.
///
/// Tables information is obtained by executing `SQLTable` function within
/// scope of the connected database accessible with the specified connection.
/// Since this function is implemented in terms of the `SQLTable`s, it returns
/// result set ordered by TABLE_TYPE, TABLE_CAT, TABLE_SCHEM, and TABLE_NAME.
///
/// All arguments are treated as the Pattern Value Arguments.
/// Empty string argument is equivalent to passing the search pattern '%'.
catalog::tables find_tables(
const string_type& table = string_type(),
const string_type& type = string_type(),
const string_type& schema = string_type(),
const string_type& catalog = string_type());
/// \brief Creates result set with tables and the privileges associated with each table.
/// Tables information is obtained by executing `SQLTablePrivileges` function within
/// scope of the connected database accessible with the specified connection.
/// Since this function is implemented in terms of the `SQLTablePrivileges`s, it returns
/// result set ordered by TABLE_CAT, TABLE_SCHEM, TABLE_NAME, PRIVILEGE, and GRANTEE.
///
/// \param catalog The table catalog. It cannot contain a string search pattern.
/// \param schema String search pattern for schema names, treated as the Pattern Value
/// Arguments.
/// \param table String search pattern for table names, treated as the Pattern Value Arguments.
///
/// \note Due to the fact catalog cannot is not the Pattern Value Argument,
/// order of parameters is different than in the other catalog look-up functions.
catalog::table_privileges find_table_privileges(
const string_type& catalog,
const string_type& table = string_type(),
const string_type& schema = string_type());
/// \brief Creates result set with columns in one or more tables.
///
/// Columns information is obtained by executing `SQLColumns` function within
/// scope of the connected database accessible with the specified connection.
/// Since this function is implemented in terms of the `SQLColumns`, it returns
/// result set ordered by TABLE_CAT, TABLE_SCHEM, TABLE_NAME, and ORDINAL_POSITION.
///
/// All arguments are treated as the Pattern Value Arguments.
/// Empty string argument is equivalent to passing the search pattern '%'.
catalog::columns find_columns(
const string_type& column = string_type(),
const string_type& table = string_type(),
const string_type& schema = string_type(),
const string_type& catalog = string_type());
/// \brief Creates result set with columns that compose the primary key of a single table.
///
/// Returns result set with column names that make up the primary key for a table.
/// The primary key information is obtained by executing `SQLPrimaryKey` function within
/// scope of the connected database accessible with the specified connection.
///
/// All arguments are treated as the Pattern Value Arguments.
/// Empty string argument is equivalent to passing the search pattern '%'.
catalog::primary_keys find_primary_keys(
const string_type& table,
const string_type& schema = string_type(),
const string_type& catalog = string_type());
/// \brief Returns names of all catalogs (or databases) available in connected data source.
///
/// Executes `SQLTable` function with `SQL_ALL_CATALOG` as catalog search pattern.
std::list list_catalogs();
/// \brief Returns names of all schemas available in connected data source.
///
/// Executes `SQLTable` function with `SQL_ALL_SCHEMAS` as schema search pattern.
std::list list_schemas();
private:
connection conn_;
};
/// @}
// clang-format off
// 8888888888 8888888888 888 d8b
// 888 888 888 Y8P
// 888 888 888
// 8888888 888d888 .d88b. .d88b. 8888888 888 888 88888b. .d8888b 888888 888 .d88b. 88888b. .d8888b
// 888 888P" d8P Y8b d8P Y8b 888 888 888 888 "88b d88P" 888 888 d88""88b 888 "88b 88K
// 888 888 88888888 88888888 888 888 888 888 888 888 888 888 888 888 888 888 "Y8888b.
// 888 888 Y8b. Y8b. 888 Y88b 888 888 888 Y88b. Y88b. 888 Y88..88P 888 888 X88
// 888 888 "Y8888 "Y8888 888 "Y88888 888 888 "Y8888P "Y888 888 "Y88P" 888 888 88888P'
// MARK: Free Functions -
// clang-format on
/// \addtogroup mainf Free Functions
/// \brief Convenience functions.
///
/// @{
/// \brief Information on a configured ODBC driver.
struct driver
{
/// \brief Driver attributes.
struct attribute
{
nanodbc::string_type keyword; ///< Driver keyword attribute.
nanodbc::string_type value; ///< Driver attribute value.
};
nanodbc::string_type name; ///< Driver name.
std::list attributes; ///< List of driver attributes.
};
/// \brief Returns a list of ODBC drivers on your system.
std::list list_drivers();
/// \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 Opens, prepares, and executes query directly without creating result object.
/// \param conn The connection where the statement will be executed.
/// \param query The SQL query that will be executed.
/// \param batch_operations Rows to fetch per rowset, or 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
void just_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 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 and without creating result object.
/// \param stmt The prepared statement that will be executed.
/// \param batch_operations 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
void just_execute(statement& stmt, long batch_operations = 1);
/// \brief Execute the previously prepared query now.
///
/// Executes within the context of a transaction object, commits directly after execution.
/// \param stmt The prepared statement that will be executed in batch.
/// \param batch_operations 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 Execute the previously prepared query now and without creating result object.
///
/// Executes within the context of a transaction object, commits directly after execution.
/// \param stmt The prepared statement that will be executed in batch.
/// \param batch_operations 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
void just_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 stmt The prepared statement that will be executed in batch.
/// \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
#endif