2097 lines
85 KiB
C++
2097 lines
85 KiB
C++
/// \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 <a href="http://nanodbc.io/">project
|
|
/// homepage</a>.
|
|
///
|
|
/// \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
|
|
/// <div class="license">
|
|
/// Copyright (C) 2013 lexicalunit <lexicalunit@lexicalunit.com>
|
|
///
|
|
/// 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.
|
|
/// </div>
|
|
///
|
|
/// \section credits Credits
|
|
/// <div class="license">
|
|
/// 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.
|
|
/// </div>
|
|
|
|
#ifndef NANODBC_H
|
|
#define NANODBC_H
|
|
|
|
#include <cstddef>
|
|
#include <functional>
|
|
#include <list>
|
|
#include <memory>
|
|
#include <stdexcept>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include <cstdint>
|
|
|
|
/// \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 Configuration and utility macros that nanodbc uses, can be overriden by users.
|
|
///
|
|
/// @{
|
|
#ifdef DOXYGEN
|
|
|
|
/// \def NANODBC_THROW_NO_SOURCE_LOCATION
|
|
/// \brief Configures \c nanodbc::database_error message
|
|
///
|
|
/// If defined, removes source file name and line number from \c nanodbc::database_error message
|
|
/// By default, nanodbc includes source location of exception in the error message.
|
|
#define NANODBC_THROW_NO_SOURCE_LOCATION 1
|
|
|
|
/// \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 <crtdbg.h>
|
|
/// #define NANODBC_ASSERT _ASSERTE
|
|
/// #endif
|
|
/// \endcode
|
|
#define NANODBC_ASSERT(expression) assert(expression)
|
|
|
|
#endif
|
|
/// @}
|
|
|
|
#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
|
|
#ifndef NANODBC_SUPPORT_STRING_VIEW
|
|
#define NANODBC_SUPPORT_STRING_VIEW
|
|
#endif
|
|
#endif
|
|
|
|
// You must explicitly request Unicode support by defining NANODBC_ENABLE_UNICODE at compile time.
|
|
#ifndef DOXYGEN
|
|
#ifdef NANODBC_ENABLE_UNICODE
|
|
#ifdef NANODBC_USE_IODBC_WIDE_STRINGS
|
|
#define NANODBC_TEXT(s) U##s
|
|
typedef std::u32string string;
|
|
#ifdef NANODBC_SUPPORT_STRING_VIEW
|
|
typedef std::u32string_view string_view;
|
|
#endif
|
|
#else
|
|
#ifdef _MSC_VER
|
|
typedef std::wstring string;
|
|
#ifdef NANODBC_SUPPORT_STRING_VIEW
|
|
typedef std::wstring_view string_view;
|
|
#endif
|
|
#define NANODBC_TEXT(s) L##s
|
|
#else
|
|
typedef std::u16string string;
|
|
#ifdef NANODBC_SUPPORT_STRING_VIEW
|
|
typedef std::u16string_view string_view;
|
|
#endif
|
|
#define NANODBC_TEXT(s) u##s
|
|
#endif
|
|
#endif
|
|
#else
|
|
typedef std::string string;
|
|
#ifdef NANODBC_SUPPORT_STRING_VIEW
|
|
typedef std::string_view string_view;
|
|
#endif
|
|
#define NANODBC_TEXT(s) s
|
|
#endif
|
|
|
|
#ifdef NANODBC_USE_IODBC_WIDE_STRINGS
|
|
typedef std::u32string wide_string;
|
|
#ifdef NANODBC_SUPPORT_STRING_VIEW
|
|
typedef std::u32string_view wide_string_view;
|
|
#endif
|
|
#else
|
|
#ifdef _MSC_VER
|
|
typedef std::wstring wide_string;
|
|
#ifdef NANODBC_SUPPORT_STRING_VIEW
|
|
typedef std::wstring_view wide_string_view;
|
|
#endif
|
|
#else
|
|
typedef std::u16string wide_string;
|
|
#ifdef NANODBC_SUPPORT_STRING_VIEW
|
|
typedef std::u16string_view wide_string_view;
|
|
#endif
|
|
#endif
|
|
#endif
|
|
|
|
typedef wide_string::value_type wide_char_t;
|
|
|
|
#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`.
|
|
///
|
|
/// By default, the macro maps to an unprefixed string literal.
|
|
/// If building with options NANODBC_ENABLE_UNICODE=ON and
|
|
/// NANODBC_USE_IODBC_WIDE_STRINGS=ON specified, then it prefixes a literal with U"...".
|
|
/// If only NANODBC_ENABLE_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 will be \c std::u16string or \c std::32string if \c NANODBC_ENABLE_UNICODE
|
|
/// defined.
|
|
///
|
|
/// Otherwise it will be \c std::string.
|
|
typedef unspecified - type string;
|
|
/// \c null_type will be \c int64_t for 64-bit compilations, otherwise \c long.
|
|
typedef unspecified - type null_type;
|
|
#endif
|
|
|
|
#if __cplusplus >= 201402L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201402L)
|
|
// [[deprecated]] is only available in C++14
|
|
#define NANODBC_DEPRECATED [[deprecated]]
|
|
#else
|
|
#ifdef __GNUC__
|
|
#define NANODBC_DEPRECATED __attribute__((deprecated))
|
|
#elif defined(_MSC_VER)
|
|
#define NANODBC_DEPRECATED __declspec(deprecated)
|
|
#else
|
|
#define NANODBC_DEPRECATED
|
|
#endif
|
|
#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 noexcept;
|
|
};
|
|
|
|
/// \brief Accessed null data.
|
|
/// \see exceptions
|
|
class null_access_error : public std::runtime_error
|
|
{
|
|
public:
|
|
null_access_error();
|
|
const char* what() const noexcept;
|
|
};
|
|
|
|
/// \brief Index out of range.
|
|
/// \see exceptions
|
|
class index_range_error : public std::runtime_error
|
|
{
|
|
public:
|
|
index_range_error();
|
|
const char* what() const 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 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 noexcept;
|
|
long native() const noexcept;
|
|
const std::string state() const 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.
|
|
};
|
|
|
|
/// \brief A type trait for testing if a type is a std::basic_string compatible with the current
|
|
/// nanodbc configuration
|
|
template <typename T>
|
|
using is_string = std::integral_constant<
|
|
bool,
|
|
std::is_same<typename std::decay<T>::type, std::string>::value ||
|
|
std::is_same<typename std::decay<T>::type, wide_string>::value
|
|
#ifdef NANODBC_SUPPORT_STRING_VIEW
|
|
|| std::is_same<typename std::decay<T>::type, std::string_view>::value ||
|
|
std::is_same<typename std::decay<T>::type, wide_string_view>::value
|
|
#endif
|
|
>;
|
|
|
|
/// \brief A type trait for testing if a type is a character compatible with the current nanodbc
|
|
/// configuration
|
|
template <typename T>
|
|
using is_character = std::integral_constant<
|
|
bool,
|
|
std::is_same<typename std::decay<T>::type, std::string::value_type>::value ||
|
|
std::is_same<typename std::decay<T>::type, wide_char_t>::value>;
|
|
|
|
template <typename T>
|
|
using enable_if_string = typename std::enable_if<is_string<T>::value>::type;
|
|
|
|
template <typename T>
|
|
using enable_if_character = typename std::enable_if<is_character<T>::value>::type;
|
|
|
|
/// \}
|
|
|
|
/// \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);
|
|
|
|
/// Move constructor.
|
|
transaction(transaction&& rhs) noexcept;
|
|
|
|
/// Assignment.
|
|
transaction& operator=(transaction rhs);
|
|
|
|
/// Member swap.
|
|
void swap(transaction& rhs) noexcept;
|
|
|
|
/// \brief If this transaction has not been committed, will will rollback any modifying ops.
|
|
~transaction() noexcept;
|
|
|
|
/// \brief Commits transaction immediately.
|
|
/// \throws database_error
|
|
void commit();
|
|
|
|
/// \brief Marks this transaction for rollback.
|
|
void rollback() 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<transaction_impl> 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& query, long timeout = 0);
|
|
|
|
/// \brief Copy constructor.
|
|
statement(const statement& rhs);
|
|
|
|
/// \brief Move constructor.
|
|
statement(statement&& rhs) noexcept;
|
|
|
|
/// \brief Assignment.
|
|
statement& operator=(statement rhs);
|
|
|
|
/// \brief Member swap.
|
|
void swap(statement& rhs) noexcept;
|
|
|
|
/// \brief Closes the statement.
|
|
/// \see close()
|
|
~statement() 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& 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& 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& 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& 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& 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);
|
|
|
|
/// \brief Completes a previously initiated asynchronous query execution, returning the result.
|
|
///
|
|
/// \deprecated Use complete_execute instead.
|
|
NANODBC_DEPRECATED 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& 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& catalog,
|
|
const string& schema,
|
|
const string& procedure,
|
|
const string& 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() 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 <class T>
|
|
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_direction ODBC parameter direction.
|
|
/// \throws database_error
|
|
///
|
|
/// @{
|
|
|
|
/// \brief Binds multiple values.
|
|
/// \see bind_multi
|
|
template <class T>
|
|
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 <class T>
|
|
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 <class T>
|
|
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<std::vector<uint8_t>> const& values,
|
|
param_direction direction = PARAM_IN);
|
|
|
|
/// \brief Binds multiple values.
|
|
/// \see bind_multi
|
|
void bind(
|
|
short param_index,
|
|
std::vector<std::vector<uint8_t>> const& values,
|
|
bool const* nulls,
|
|
param_direction direction = PARAM_IN);
|
|
|
|
/// \brief Binds multiple values.
|
|
/// \see bind_multi
|
|
void bind(
|
|
short param_index,
|
|
std::vector<std::vector<uint8_t>> 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_direction ODBC parameter direction.
|
|
/// \throws database_error
|
|
///
|
|
/// @{
|
|
|
|
/// \brief Binds multiple string values.
|
|
/// \see bind_strings
|
|
template <class T, typename = enable_if_character<T>>
|
|
void bind_strings(
|
|
short param_index,
|
|
T 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
|
|
template <class T, typename = enable_if_string<T>>
|
|
void bind_strings(
|
|
short param_index,
|
|
std::vector<T> const& values,
|
|
param_direction direction = PARAM_IN);
|
|
|
|
/// \brief Binds multiple string values.
|
|
/// \see bind_strings
|
|
template <
|
|
std::size_t BatchSize,
|
|
std::size_t ValueSize,
|
|
class T,
|
|
typename = enable_if_character<T>>
|
|
void bind_strings(
|
|
short param_index,
|
|
T const (&values)[BatchSize][ValueSize],
|
|
param_direction direction = PARAM_IN)
|
|
{
|
|
auto param_values = reinterpret_cast<T const*>(values);
|
|
bind_strings(param_index, param_values, ValueSize, BatchSize, direction);
|
|
}
|
|
|
|
/// \brief Binds multiple string values.
|
|
/// \see bind_strings
|
|
template <class T, typename = enable_if_character<T>>
|
|
void bind_strings(
|
|
short param_index,
|
|
T const* values,
|
|
std::size_t value_size,
|
|
std::size_t batch_size,
|
|
T const* null_sentry,
|
|
param_direction direction = PARAM_IN);
|
|
|
|
/// \brief Binds multiple string values.
|
|
/// \see bind_strings
|
|
template <class T, typename = enable_if_string<T>>
|
|
void bind_strings(
|
|
short param_index,
|
|
std::vector<T> const& values,
|
|
typename T::value_type const* null_sentry,
|
|
param_direction direction = PARAM_IN);
|
|
|
|
/// \brief Binds multiple string values.
|
|
/// \see bind_strings
|
|
template <
|
|
std::size_t BatchSize,
|
|
std::size_t ValueSize,
|
|
class T,
|
|
typename = enable_if_character<T>>
|
|
void bind_strings(
|
|
short param_index,
|
|
T const (&values)[BatchSize][ValueSize],
|
|
T const* null_sentry,
|
|
param_direction direction = PARAM_IN)
|
|
{
|
|
auto param_values = reinterpret_cast<T const*>(values);
|
|
bind_strings(param_index, param_values, ValueSize, BatchSize, null_sentry, direction);
|
|
}
|
|
|
|
/// \brief Binds multiple string values.
|
|
/// \see bind_strings
|
|
template <class T, typename = enable_if_character<T>>
|
|
void bind_strings(
|
|
short param_index,
|
|
T 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
|
|
template <class T, typename = enable_if_string<T>>
|
|
void bind_strings(
|
|
short param_index,
|
|
std::vector<T> const& values,
|
|
bool const* nulls,
|
|
param_direction direction = PARAM_IN);
|
|
|
|
/// \brief Binds multiple string values.
|
|
/// \see bind_strings
|
|
template <
|
|
std::size_t BatchSize,
|
|
std::size_t ValueSize,
|
|
class T,
|
|
typename = enable_if_character<T>>
|
|
void bind_strings(
|
|
short param_index,
|
|
T const (&values)[BatchSize][ValueSize],
|
|
bool const* nulls,
|
|
param_direction direction = PARAM_IN)
|
|
{
|
|
auto param_values = reinterpret_cast<T const*>(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);
|
|
|
|
/// @}
|
|
|
|
/// \brief Sets descriptions for parameters in the prepared statement.
|
|
///
|
|
/// If your prepared SQL query has any parameter markers, ? (question mark)
|
|
/// placeholders this is how you can describe the SQL type, size and scale
|
|
/// for some or all of the parameters, prior to binding any data to the
|
|
/// parameters. Calling this method is optional: if a parameter is not
|
|
/// described using a call to this method, then during a bind an attempt is
|
|
/// made to identify it using a call to the ODBC SQLDescribeParam API handle.
|
|
/// Once set, description is re-used for possibly repeated binds
|
|
/// execution and only cleared when the statement is cleared / destroyed.
|
|
/// Parameter markers are numbered using Zero-based index from left to right.
|
|
///
|
|
/// \param idx Vector of zero-based indices of parameters we are describing.
|
|
/// \param type Vector of (short integer) types.
|
|
/// \param size Vector of (unsigned long) sizes.
|
|
/// \param scale Vector of (short integer) decimal precision / scale.
|
|
/// \throws programming_error
|
|
void describe_parameters(
|
|
const std::vector<short>& idx,
|
|
const std::vector<short>& type,
|
|
const std::vector<unsigned long>& size,
|
|
const std::vector<short>& scale);
|
|
|
|
/// @}
|
|
private:
|
|
typedef std::function<bool(std::size_t)> null_predicate_type;
|
|
|
|
private:
|
|
class statement_impl;
|
|
friend class nanodbc::result;
|
|
|
|
private:
|
|
std::shared_ptr<statement_impl> 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);
|
|
|
|
/// Move constructor.
|
|
connection(connection&& rhs) noexcept;
|
|
|
|
/// Assignment.
|
|
connection& operator=(connection rhs);
|
|
|
|
/// Member swap.
|
|
void swap(connection&) noexcept;
|
|
|
|
/// \brief Create new connection object and immediately connect to the given data source.
|
|
///
|
|
/// The function calls ODBC API SQLConnect.
|
|
///
|
|
/// \param dsn The name of the data source name (DSN).
|
|
/// \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& dsn, const string& user, const string& pass, long timeout = 0);
|
|
|
|
/// \brief Create new connection object and immediately connect using the given connection
|
|
/// string.
|
|
///
|
|
/// The function calls ODBC API SQLDriverConnect.
|
|
///
|
|
/// \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& 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() noexcept;
|
|
|
|
/// \brief Allocate environment and connection handles.
|
|
///
|
|
/// Allows on-demand allocation of handles to configure the ODBC environment
|
|
/// and attributes, before database connection is established.
|
|
/// Typically, user does not have to make this call explicitly.
|
|
///
|
|
/// \throws database_error
|
|
/// \see deallocate()
|
|
void allocate();
|
|
|
|
/// \brief Release environment and connection handles.
|
|
/// \see allocate()
|
|
void deallocate();
|
|
|
|
/// \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& dsn, const string& user, const string& 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& 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& dsn,
|
|
const string& user,
|
|
const string& 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& 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 or fixed-size value.
|
|
/// The general information about the driver and data source associated
|
|
/// with a connection is obtained using `SQLGetInfo` function.
|
|
template <class T>
|
|
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 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 dbms_version() const;
|
|
|
|
/// \brief Returns the name of the ODBC driver.
|
|
/// \throws database_error
|
|
string 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 database_name() const;
|
|
|
|
/// \brief Returns the name of the current catalog.
|
|
/// Returns the current setting of the connection attribute SQL_ATTR_CURRENT_CATALOG.
|
|
string 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<connection_impl> 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() noexcept;
|
|
|
|
/// \brief Copy constructor.
|
|
result(const result& rhs);
|
|
|
|
/// \brief Move constructor.
|
|
result(result&& rhs) noexcept;
|
|
|
|
/// \brief Assignment.
|
|
result& operator=(result rhs);
|
|
|
|
/// \brief Member swap.
|
|
void swap(result& rhs) 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 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 Reports if number of affected rows is available.
|
|
/// \return true if number of affected rows is known, regardless of the value;
|
|
/// false if the number is not available.
|
|
/// \throws database_error
|
|
/// \code{.cpp}
|
|
/// assert(r.has_affected_rows() == (r.affected_rows() >= 0));
|
|
/// \endcode
|
|
bool has_affected_rows() const;
|
|
|
|
/// \brief Rows in the current rowset or 0 if the number of rows is not available.
|
|
long rows() const 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 noexcept;
|
|
|
|
/// \brief Unbind data buffers for all columns in the result set.
|
|
///
|
|
/// Wraps unbind(short column)
|
|
/// \throws index_range_error, database_error
|
|
void unbind();
|
|
|
|
/// \brief Unbind data buffers for specific columns in the result set.
|
|
///
|
|
/// Wraps unbind(short column)
|
|
///
|
|
/// \param column_name string Name of column we wish to unbind.
|
|
/// \throws index_range_error, database_error
|
|
void unbind(const string& column_name);
|
|
|
|
/// \brief Unbind data buffers for specific columns in the result set.
|
|
///
|
|
/// When a result is constructed, in order to optimize data retrieval,
|
|
/// we automatically try to bind buffers, except for columns that contain
|
|
/// long/blob data types. This method gives the caller the option to unbind
|
|
/// a specific buffer. Subsequently, during calls to get(), if there is no
|
|
/// bound data buffer, we will attempt to retrieve the data using a call
|
|
/// SQLGetData; this is similar to the route taken for columns hosting long
|
|
/// or bloby data types. This is suboptimal from efficiency perspective,
|
|
/// however may be necessary of the driver we are communicating with does
|
|
/// not support out-of-order retrieval of long data.
|
|
///
|
|
/// \param column short Zero-based index of column we wish to unbind.
|
|
/// \throws index_range_error, database_error
|
|
void unbind(short column);
|
|
|
|
/// \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 <class T>
|
|
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 <class T>
|
|
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 <class T>
|
|
void get_ref(const string& 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 <class T>
|
|
void get_ref(const string& 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 <class T>
|
|
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 <class T>
|
|
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 <class T>
|
|
T get(const string& 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 <class T>
|
|
T get(const string& 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& column_name) const;
|
|
|
|
/// \brief Returns true if we have bound a buffer to the given column.
|
|
///
|
|
/// Generically, nanodbc will greedily bind buffers to columns in the result
|
|
/// set. However, we have also given the user the ability to unbind buffers
|
|
/// via unbind() forcing nanodbc to retrieve data via SQLGetData. This
|
|
/// method returns true if there is a buffer bound to the column.
|
|
///
|
|
/// Columns are numbered from left to right and 0-indexed.
|
|
/// \param column short position.
|
|
/// \throws index_range_error
|
|
bool is_bound(short column) const;
|
|
|
|
/// \brief Returns true if we have bound a buffer to the given column.
|
|
///
|
|
/// See is_bound(short column) for details.
|
|
/// \see is_bound()
|
|
/// \param column_name column's name.
|
|
/// \throws index_range_error
|
|
bool is_bound(const string& 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& 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 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& 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& 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& column_name) const;
|
|
|
|
/// \brief Returns data source dependent data type name of this column.
|
|
///
|
|
/// The function calls SQLCoLAttribute with the field attribute SQL_DESC_TYPE_NAME to
|
|
/// obtain the data type name.
|
|
/// If the type is unknown, an empty string is returned.
|
|
/// \note Unlike other column metadata functions (eg. column_datatype()),
|
|
/// this function cost is an extra ODBC API call.
|
|
string column_datatype_name(short column) const;
|
|
|
|
/// \brief Returns data source dependent data type name of this column by name.
|
|
///
|
|
/// The function calls SQLCoLAttribute with the field attribute SQL_DESC_TYPE_NAME to
|
|
/// obtain the data type name.
|
|
/// If the type is unknown, an empty string is returned.
|
|
/// \note Unlike other column metadata functions (eg. column_datatype()),
|
|
/// this function cost is an extra ODBC API call.
|
|
string column_datatype_name(const string& 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& 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<result_impl> 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.
|
|
explicit 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 table_catalog() const; ///< Fetch table catalog.
|
|
string table_schema() const; ///< Fetch table schema.
|
|
string table_name() const; ///< Fetch table name.
|
|
string table_type() const; ///< Fetch table type.
|
|
string 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 table_catalog() const; ///< Fetch table catalog.
|
|
string table_schema() const; ///< Fetch table schema.
|
|
string table_name() const; ///< Fetch table name.
|
|
string column_name() const; ///< Fetch column name.
|
|
short data_type() const; ///< Fetch column data type.
|
|
string 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 remarks() const; ///< Fetch column remarks.
|
|
string 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 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 table_catalog() const; ///< Fetch table catalog.
|
|
string table_schema() const; ///< Fetch table schema.
|
|
string table_name() const; ///< Fetch table name.
|
|
string 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 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 table_catalog() const; ///< Fetch table catalog.
|
|
string table_schema() const; ///< Fetch table schema.
|
|
string table_name() const; ///< Fetch table name.
|
|
string grantor() const; ///< Fetch name of user who granted the privilege.
|
|
string grantee() const; ///< Fetch name of user whom the privilege was granted.
|
|
string privilege() const; ///< Fetch the table privilege.
|
|
/// Fetch indicator whether the grantee is permitted to grant the privilege to other users.
|
|
string is_grantable() const;
|
|
|
|
private:
|
|
friend class nanodbc::catalog;
|
|
table_privileges(result& find_result);
|
|
result result_;
|
|
};
|
|
|
|
/// \brief Result set for a list of procedures in the data source.
|
|
class procedures
|
|
{
|
|
public:
|
|
bool next(); ///< Move to the next result in the result set.
|
|
string procedure_catalog() const; ///< Fetch procedure catalog.
|
|
string procedure_schema() const; ///< Fetch procedure schema.
|
|
string procedure_name() const; ///< Fetch procedure name.
|
|
string procedure_remarks() const; ///< Fetch procedure remarks.
|
|
short procedure_type() const; ///< Fetch procedure type.
|
|
|
|
private:
|
|
friend class nanodbc::catalog;
|
|
procedures(result& find_result);
|
|
result result_;
|
|
};
|
|
|
|
/// \brief Result set for a list of procedures in the data source.
|
|
class procedure_columns
|
|
{
|
|
public:
|
|
bool next(); ///< Move to the next result in the result set.
|
|
string procedure_catalog() const; ///< Fetch procedure catalog.
|
|
string procedure_schema() const; ///< Fetch procedure schema.
|
|
string procedure_name() const; ///< Fetch procedure name.
|
|
string column_name() const; ///< Fetch column name.
|
|
short column_type() const; ///< Fetch column type.
|
|
short data_type() const; ///< Fetch column data type.
|
|
string 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 remarks() const; ///< Fetch column remarks.
|
|
string 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 is_nullable() const;
|
|
|
|
private:
|
|
friend class nanodbc::catalog;
|
|
procedure_columns(result& find_result);
|
|
result result_;
|
|
};
|
|
|
|
/// \brief Creates catalog operating on database accessible through the specified connection.
|
|
explicit 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& table = string(),
|
|
const string& type = string(),
|
|
const string& schema = string(),
|
|
const string& catalog = string());
|
|
|
|
/// \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& catalog,
|
|
const string& table = string(),
|
|
const string& schema = string());
|
|
|
|
/// \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& column = string(),
|
|
const string& table = string(),
|
|
const string& schema = string(),
|
|
const string& catalog = string());
|
|
|
|
/// \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& table,
|
|
const string& schema = string(),
|
|
const string& catalog = string());
|
|
|
|
/// \brief Creates result set with catalog, schema, procedure, and procedure types.
|
|
///
|
|
/// Procedure information is obtained by executing `SQLProcedures` function within
|
|
/// scope of the connected database accessible with the specified connection.
|
|
/// Since this function is implemented in terms of the `SQLProcedures`s, it returns
|
|
/// result set ordered by PROCEDURE_CAT, PROCEDUORE_SCHEM, and PROCEDURE_NAME.
|
|
///
|
|
/// All arguments are treated as the Pattern Value Arguments.
|
|
/// Empty string argument is equivalent to passing the search pattern '%'.
|
|
|
|
catalog::procedures find_procedures(
|
|
const string& procedure = string(),
|
|
const string& schema = string(),
|
|
const string& catalog = string());
|
|
|
|
/// \brief Creates result set with columns in one or more procedures.
|
|
///
|
|
/// Columns information is obtained by executing `SQLProcedureColumns` function within
|
|
/// scope of the connected database accessible with the specified connection.
|
|
/// Since this function is implemented in terms of the `SQLProcedureColumns`, it returns
|
|
/// result set ordered by PROCEDURE_CAT, PROCEDURE_SCHEM, PROCEDURE_NAME, and
|
|
/// COLUMN_TYPE.
|
|
///
|
|
/// All arguments are treated as the Pattern Value Arguments.
|
|
/// Empty string argument is equivalent to passing the search pattern '%'.
|
|
catalog::procedure_columns find_procedure_columns(
|
|
const string& column = string(),
|
|
const string& procedure = string(),
|
|
const string& schema = string(),
|
|
const string& catalog = string());
|
|
|
|
/// \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<string> 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<string> 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 keyword; ///< Driver keyword attribute.
|
|
nanodbc::string value; ///< Driver attribute value.
|
|
};
|
|
|
|
nanodbc::string name; ///< Driver name.
|
|
std::list<attribute> attributes; ///< List of driver attributes.
|
|
};
|
|
|
|
struct datasource
|
|
{
|
|
nanodbc::string name; ///< DSN name.
|
|
nanodbc::string driver; ///< Driver description.
|
|
};
|
|
|
|
/// \brief Returns a list of ODBC drivers on your system.
|
|
std::list<driver> list_drivers();
|
|
|
|
/// \brief Returns a list of ODBC data sources on your system.
|
|
std::list<datasource> list_datasources();
|
|
|
|
/// \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& 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& 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& query, long timeout = 0);
|
|
|
|
/// @}
|
|
|
|
} // namespace nanodbc
|
|
|
|
#endif
|