From 63d9cbb434ec4f6e828083b99d638127cfce7a95 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Thu, 24 Dec 2015 04:08:56 +0000 Subject: ODBC files prefixed with odbc- --- libodbcpp/Jamfile.jam | 2 +- libodbcpp/bind.cpp | 11 -- libodbcpp/bind.h | 21 --- libodbcpp/client.h | 7 - libodbcpp/column.cpp | 106 --------------- libodbcpp/column.h | 131 ------------------- libodbcpp/command.cpp | 40 ------ libodbcpp/command.h | 52 -------- libodbcpp/connection.cpp | 273 --------------------------------------- libodbcpp/connection.h | 56 -------- libodbcpp/dsn.cpp | 13 -- libodbcpp/dsn.h | 18 --- libodbcpp/error.cpp | 86 ------------ libodbcpp/error.h | 24 ---- libodbcpp/mock.cpp | 32 ----- libodbcpp/mock.h | 25 ---- libodbcpp/modifycommand.cpp | 40 ------ libodbcpp/modifycommand.h | 18 --- libodbcpp/odbc-bind.cpp | 11 ++ libodbcpp/odbc-bind.h | 21 +++ libodbcpp/odbc-client.h | 7 + libodbcpp/odbc-column.cpp | 106 +++++++++++++++ libodbcpp/odbc-column.h | 131 +++++++++++++++++++ libodbcpp/odbc-command.cpp | 40 ++++++ libodbcpp/odbc-command.h | 52 ++++++++ libodbcpp/odbc-connection.cpp | 273 +++++++++++++++++++++++++++++++++++++++ libodbcpp/odbc-connection.h | 56 ++++++++ libodbcpp/odbc-dsn.cpp | 13 ++ libodbcpp/odbc-dsn.h | 18 +++ libodbcpp/odbc-error.cpp | 86 ++++++++++++ libodbcpp/odbc-error.h | 24 ++++ libodbcpp/odbc-mock.cpp | 32 +++++ libodbcpp/odbc-mock.h | 25 ++++ libodbcpp/odbc-modifycommand.cpp | 40 ++++++ libodbcpp/odbc-modifycommand.h | 18 +++ libodbcpp/odbc-param.cpp | 124 ++++++++++++++++++ libodbcpp/odbc-param.h | 135 +++++++++++++++++++ libodbcpp/odbc-selectcommand.cpp | 144 +++++++++++++++++++++ libodbcpp/odbc-selectcommand.h | 22 ++++ libodbcpp/param.cpp | 124 ------------------ libodbcpp/param.h | 135 ------------------- libodbcpp/selectcommand.cpp | 144 --------------------- libodbcpp/selectcommand.h | 22 ---- libodbcpp/unittests/testodbc.cpp | 2 +- 44 files changed, 1380 insertions(+), 1380 deletions(-) delete mode 100644 libodbcpp/bind.cpp delete mode 100644 libodbcpp/bind.h delete mode 100644 libodbcpp/client.h delete mode 100644 libodbcpp/column.cpp delete mode 100644 libodbcpp/column.h delete mode 100644 libodbcpp/command.cpp delete mode 100644 libodbcpp/command.h delete mode 100644 libodbcpp/connection.cpp delete mode 100644 libodbcpp/connection.h delete mode 100644 libodbcpp/dsn.cpp delete mode 100644 libodbcpp/dsn.h delete mode 100644 libodbcpp/error.cpp delete mode 100644 libodbcpp/error.h delete mode 100644 libodbcpp/mock.cpp delete mode 100644 libodbcpp/mock.h delete mode 100644 libodbcpp/modifycommand.cpp delete mode 100644 libodbcpp/modifycommand.h create mode 100644 libodbcpp/odbc-bind.cpp create mode 100644 libodbcpp/odbc-bind.h create mode 100644 libodbcpp/odbc-client.h create mode 100644 libodbcpp/odbc-column.cpp create mode 100644 libodbcpp/odbc-column.h create mode 100644 libodbcpp/odbc-command.cpp create mode 100644 libodbcpp/odbc-command.h create mode 100644 libodbcpp/odbc-connection.cpp create mode 100644 libodbcpp/odbc-connection.h create mode 100644 libodbcpp/odbc-dsn.cpp create mode 100644 libodbcpp/odbc-dsn.h create mode 100644 libodbcpp/odbc-error.cpp create mode 100644 libodbcpp/odbc-error.h create mode 100644 libodbcpp/odbc-mock.cpp create mode 100644 libodbcpp/odbc-mock.h create mode 100644 libodbcpp/odbc-modifycommand.cpp create mode 100644 libodbcpp/odbc-modifycommand.h create mode 100644 libodbcpp/odbc-param.cpp create mode 100644 libodbcpp/odbc-param.h create mode 100644 libodbcpp/odbc-selectcommand.cpp create mode 100644 libodbcpp/odbc-selectcommand.h delete mode 100644 libodbcpp/param.cpp delete mode 100644 libodbcpp/param.h delete mode 100644 libodbcpp/selectcommand.cpp delete mode 100644 libodbcpp/selectcommand.h (limited to 'libodbcpp') diff --git a/libodbcpp/Jamfile.jam b/libodbcpp/Jamfile.jam index 7dd6a35..4121da7 100644 --- a/libodbcpp/Jamfile.jam +++ b/libodbcpp/Jamfile.jam @@ -23,5 +23,5 @@ lib dbpp-odbc : build-project unittests ; -package.install install : . : : dbpp-odbc : [ glob *.h ] ; +package.install install : . : : dbpp-odbc : [ glob odbc-*.h ] ; diff --git a/libodbcpp/bind.cpp b/libodbcpp/bind.cpp deleted file mode 100644 index d29fce8..0000000 --- a/libodbcpp/bind.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "bind.h" - -ODBC::Bind::Bind() -{ -} - -ODBC::Bind::~Bind() -{ -} - - diff --git a/libodbcpp/bind.h b/libodbcpp/bind.h deleted file mode 100644 index 356723b..0000000 --- a/libodbcpp/bind.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef ODBC_BIND_H -#define ODBC_BIND_H - -#include -#include - -namespace ODBC { - class Bind { - public: - Bind(); - virtual ~Bind() = 0; - - virtual SQLSMALLINT ctype() const = 0; // The C type ID - virtual SQLULEN size() const = 0; // The size of the data - protected: - mutable SQLLEN bindLen; // How much data the driver wants to store - }; -} - -#endif - diff --git a/libodbcpp/client.h b/libodbcpp/client.h deleted file mode 100644 index ac76b3f..0000000 --- a/libodbcpp/client.h +++ /dev/null @@ -1,7 +0,0 @@ -#include "column.h" -#include "command.h" -#include "connection.h" -#include "dsn.h" -#include "modifycommand.h" -#include "param.h" -#include "selectcommand.h" diff --git a/libodbcpp/column.cpp b/libodbcpp/column.cpp deleted file mode 100644 index da31ed0..0000000 --- a/libodbcpp/column.cpp +++ /dev/null @@ -1,106 +0,0 @@ -#include -#include -#include -#include "column.h" -#include "command.h" -#include "selectcommand.h" -#include "error.h" - -ODBC::Column::Column(SelectCommand * sc, const Glib::ustring & s, unsigned int i) : - DB::Column(s, i), - selectCmd(sc) -{ - bindLen = 0; -} - -ODBC::Column::~Column() -{ -} - -bool -ODBC::Column::resize() -{ - return false; -} - -bool -ODBC::CharArrayColumn::resize() -{ - if (bindLen >= SQLLEN(data.size())) { - data.resize(bindLen + 1); - Column::bind(); - if (paramCmd) { - paramBound = false; - Param::bind(); - } - return true; - } - return false; -} - -bool -ODBC::Column::isNull() const -{ - return (bindLen == SQL_NULL_DATA); -} - -void -ODBC::Column::rebind(DB::Command * cmd, unsigned int idx) const -{ - meAsAParam()->paramCmd = dynamic_cast(cmd); - meAsAParam()->paramIdx = idx; - meAsAParam()->bind(); -} - -void -ODBC::Column::bind() -{ - RETCODE rc = SQLBindCol(selectCmd->hStmt, colNo + 1, ctype(), rwDataAddress(), size(), &bindLen); - if (!SQL_SUCCEEDED(rc)) { - throw Error(rc, SQL_HANDLE_STMT, selectCmd->hStmt, "ODBC::Column::bind"); - } -} - -ODBC::TimeStampColumn::operator boost::posix_time::ptime() const -{ - return boost::posix_time::ptime( - boost::gregorian::date(data.year, data.month, data.day), - boost::posix_time::time_duration(data.hour, data.minute, data.second, data.fraction)); -} -ODBC::IntervalColumn::operator boost::posix_time::time_duration() const -{ - auto dur = boost::posix_time::time_duration( - (24 * data.intval.day_second.day) + data.intval.day_second.hour, - data.intval.day_second.minute, data.intval.day_second.second, data.intval.day_second.fraction); - return (data.interval_sign ? -dur : dur); -} -void -ODBC::SignedIntegerColumn::apply(DB::HandleField & h) const -{ - if (isNull()) return h.null(); - h.integer(data); -} -void -ODBC::FloatingPointColumn::apply(DB::HandleField & h) const -{ - if (isNull()) return h.null(); - h.floatingpoint(data); -} -void -ODBC::CharArrayColumn::apply(DB::HandleField & h) const -{ - if (isNull()) return h.null(); - h.string(&data.front(), bindLen); -} -void -ODBC::TimeStampColumn::apply(DB::HandleField & h) const -{ - if (isNull()) return h.null(); - h.timestamp(*this); -} -void -ODBC::IntervalColumn::apply(DB::HandleField & h) const -{ - if (isNull()) return h.null(); - h.interval(*this); -} diff --git a/libodbcpp/column.h b/libodbcpp/column.h deleted file mode 100644 index c39a0f2..0000000 --- a/libodbcpp/column.h +++ /dev/null @@ -1,131 +0,0 @@ -#ifndef ODBC_COLUMN_H -#define ODBC_COLUMN_H - -#include -#include -#include -#include -#include "bind.h" -#include "param.h" - -namespace ODBC { - class SelectCommand; - class Column : public virtual Bind, public virtual DB::Column { - public: - Column(SelectCommand *, const Glib::ustring & s, unsigned int i); - virtual ~Column() = 0; - void bind(); - virtual void * rwDataAddress() = 0; - void rebind(DB::Command *, unsigned int idx) const; - virtual bool resize(); - - virtual operator int () const { throw std::bad_cast(); } - virtual operator long () const { throw std::bad_cast(); } - virtual operator long long () const { throw std::bad_cast(); } - virtual operator unsigned int () const { throw std::bad_cast(); } - virtual operator unsigned long () const { throw std::bad_cast(); } - virtual operator unsigned long long () const { throw std::bad_cast(); } - - virtual operator double () const { throw std::bad_cast(); } - virtual operator float () const { throw std::bad_cast(); } - - virtual operator std::string () const { throw std::bad_cast(); } - virtual operator Glib::ustring () const { throw std::bad_cast(); } - - virtual operator struct tm () const { throw std::bad_cast(); } - virtual operator SQL_TIMESTAMP_STRUCT () const { throw std::bad_cast(); } - - bool isNull() const; - virtual void apply(DB::HandleField &) const = 0; - - const SelectCommand * selectCmd; - protected: - virtual const Param * meAsAParam() const = 0; - }; - class CharArrayColumn : public Column, public Param { - public: - typedef std::vector CharArray; - CharArrayColumn(SelectCommand * sc, const Glib::ustring & n, unsigned int i, SQLULEN sizeHint) : - DB::Column(n, i), - Column(sc, n, i) - { - data.resize(std::max(sizeHint, 64) + 1); - } - virtual SQLSMALLINT ctype() const { return SQL_C_CHAR; } - virtual SQLSMALLINT stype() const { return SQL_CHAR; } - virtual SQLULEN size() const { return data.size(); } - virtual SQLINTEGER dp() const { return 0; } - virtual const void * dataAddress() const { return &data.front(); } - virtual void * rwDataAddress() { return &data.front(); } - void operator=(const Glib::ustring & d); - bool resize(); - virtual operator std::string () const { return std::string(&data.front(), bindLen); } - virtual operator Glib::ustring () const { return std::string(&data.front(), bindLen); } - virtual void apply(DB::HandleField &) const; - protected: - virtual const Param * meAsAParam() const { return this; } - CharArray data; - }; - class SignedIntegerColumn : public Column, public SignedIntegerParam { - public: - SignedIntegerColumn(SelectCommand * sc, const Glib::ustring & n, unsigned int i) : - DB::Column(n, i), - Column(sc, n, i) { } - virtual SQLSMALLINT ctype() const { return SignedIntegerParam::ctype(); } - virtual SQLULEN size() const { return SignedIntegerParam::size(); } - virtual void * rwDataAddress() { return &data; } - virtual operator int () const { return data; } - virtual operator long () const { return data; } - virtual operator long long () const { return data; } - virtual const Param * meAsAParam() const { return this; } - virtual void apply(DB::HandleField &) const; - }; -#ifdef COMPLETENESS - class UnsignedIntegerColumn : public Column, public UnsignedIntegerParam { - public: - UnsignedIntegerColumn(SelectCommand * sc, const Glib::ustring & n, unsigned int i) : - Column(sc, n, i) { } - virtual const Param * meAsAParam() const { return this; } - }; -#endif - class FloatingPointColumn : public Column, public FloatingPointParam { - public: - FloatingPointColumn(SelectCommand * sc, const Glib::ustring & n, unsigned int i) : - DB::Column(n, i), - Column(sc, n, i) { } - virtual SQLSMALLINT ctype() const { return FloatingPointParam::ctype(); } - virtual SQLULEN size() const { return FloatingPointParam::size(); } - virtual void * rwDataAddress() { return &data; } - virtual operator double () const { return data; } - virtual operator float () const { return data; } - virtual const Param * meAsAParam() const { return this; } - virtual void apply(DB::HandleField &) const; - }; - class IntervalColumn : public Column, public IntervalParam { - public: - IntervalColumn(SelectCommand * sc, const Glib::ustring & n, unsigned int i) : - DB::Column(n, i), - Column(sc, n, i) { } - virtual SQLSMALLINT ctype() const { return IntervalParam::ctype(); } - virtual SQLULEN size() const { return IntervalParam::size(); } - virtual void * rwDataAddress() { return &data; } - virtual operator boost::posix_time::time_duration () const; - virtual const Param * meAsAParam() const { return this; } - virtual void apply(DB::HandleField &) const; - }; - class TimeStampColumn : public Column, public TimeStampParam { - public: - TimeStampColumn(SelectCommand * sc, const Glib::ustring & n, unsigned int i) : - DB::Column(n, i), - Column(sc, n, i) { } - virtual SQLSMALLINT ctype() const { return TimeStampParam::ctype(); } - virtual SQLULEN size() const { return TimeStampParam::size(); } - virtual void * rwDataAddress() { return &data; } - virtual operator boost::posix_time::ptime () const; - virtual const Param * meAsAParam() const { return this; } - virtual void apply(DB::HandleField &) const; - }; -} - -#endif - diff --git a/libodbcpp/command.cpp b/libodbcpp/command.cpp deleted file mode 100644 index 801060f..0000000 --- a/libodbcpp/command.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include "command.h" -#include "error.h" -#include "param.h" -#include - -ODBC::Command::Command(const Connection & c, const std::string & s) : - DB::Command(s), - connection(c) -{ - RETCODE rc = SQLAllocHandle(SQL_HANDLE_STMT, c.conn, &hStmt); - if (!SQL_SUCCEEDED(rc)) { - throw Error(rc, SQL_HANDLE_STMT, hStmt, "Allocate statement handle"); - } - rc = SQLSetStmtAttr(hStmt, SQL_ATTR_CURSOR_TYPE, (SQLPOINTER)SQL_CURSOR_DYNAMIC, 0); - if (!SQL_SUCCEEDED(rc)) { - throw ConnectionError(rc, SQL_HANDLE_STMT, hStmt, "Set scrollable cursor"); - } - rc = SQLPrepare(hStmt, (SQLCHAR*)sql.c_str(), sql.length()); - if (!SQL_SUCCEEDED(rc)) { - SQLFreeHandle(SQL_HANDLE_STMT, hStmt); - throw Error(rc, SQL_HANDLE_STMT, hStmt, "Prepare statement"); - } - SQLSMALLINT pcount; - rc = SQLNumParams(hStmt, &pcount); - if (!SQL_SUCCEEDED(rc)) { - SQLFreeHandle(SQL_HANDLE_STMT, hStmt); - throw Error(rc, SQL_HANDLE_STMT, hStmt, "Parameter count"); - } - params.resize(pcount); -} - -ODBC::Command::~Command() -{ - for (Params::iterator i = params.begin(); i != params.end(); ++i) { - if (*i) { - delete *i; - } - } -} - diff --git a/libodbcpp/command.h b/libodbcpp/command.h deleted file mode 100644 index 14b2cbb..0000000 --- a/libodbcpp/command.h +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef ODBC_COMMAND_H -#define ODBC_COMMAND_H - -#include -#include -#include "connection.h" -#include - -namespace ODBC { - class Param; - class Command : public virtual DB::Command { - typedef std::vector Params; - public: - Command(const Connection &, const std::string & sql); - virtual ~Command() = 0; - - void bindParamI(unsigned int i, int val); - void bindParamI(unsigned int i, long val); - void bindParamI(unsigned int i, long long val); - void bindParamI(unsigned int i, unsigned int val); - void bindParamI(unsigned int i, unsigned long int val); - void bindParamI(unsigned int i, unsigned long long int val); - - void bindParamB(unsigned int i, bool val); - - void bindParamF(unsigned int i, double val); - void bindParamF(unsigned int i, float val); - - void bindParamS(unsigned int i, const Glib::ustring &); - - void bindParamT(unsigned int i, const boost::posix_time::time_duration &); - void bindParamT(unsigned int i, const boost::posix_time::ptime &); - - void bindNull(unsigned int i); - - protected: - friend class Param; - friend class Column; - SQLHSTMT hStmt; - const Connection& connection; - private: - Params params; - - template - ParamType * - makeParam(unsigned int idx); - }; - -} - -#endif - diff --git a/libodbcpp/connection.cpp b/libodbcpp/connection.cpp deleted file mode 100644 index 7e71b94..0000000 --- a/libodbcpp/connection.cpp +++ /dev/null @@ -1,273 +0,0 @@ -#include -#include -#include -#include -#include -#include "connection.h" -#include "selectcommand.h" -#include "modifycommand.h" -#include "error.h" - -NAMEDFACTORY("odbc", ODBC::Connection, DB::ConnectionFactory); - -ODBC::Connection::Connection(const DSN& d) : - env(0), - conn(0), - thinkDelStyle(DB::BulkDeleteUsingUsing), - thinkUpdStyle(DB::BulkUpdateUsingFromSrc), - txDepth(0), - txAborted(false) -{ - connectPre(); - RETCODE dberr = SQLConnect(conn, (SQLCHAR*)d.dsn.c_str(), SQL_NTS, - (SQLCHAR*)d.username.c_str(), SQL_NTS, (SQLCHAR*)d.password.c_str(), SQL_NTS); - if (!SQL_SUCCEEDED(dberr)) { - throw ConnectionError(dberr, SQL_HANDLE_DBC, conn, "Connect"); - } - connectPost(); -} - -void -ODBC::Connection::connectPre() -{ - SQLRETURN dberr = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env); - if (!SQL_SUCCEEDED(dberr)) { - throw ConnectionError(dberr, SQL_HANDLE_ENV, env, "Allocate handle"); - } - - dberr = SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0); - if (!SQL_SUCCEEDED(dberr)) { - throw ConnectionError(dberr, SQL_HANDLE_ENV, env, "Set ODBC version"); - } - - dberr = SQLAllocHandle(SQL_HANDLE_DBC, env, &conn); - if (!SQL_SUCCEEDED(dberr)) { - throw ConnectionError(dberr, SQL_HANDLE_ENV, env, "Allocate DBC handle"); - } - - dberr = SQLSetConnectAttr(conn, SQL_LOGIN_TIMEOUT, (SQLPOINTER *)5, 0); - if (!SQL_SUCCEEDED(dberr)) { - throw ConnectionError(dberr, SQL_HANDLE_ENV, env, "Set connection attributes"); - } -} - -void -ODBC::Connection::connectPost() -{ - RETCODE dberr = SQLSetConnectOption(conn, SQL_ATTR_AUTOCOMMIT, SQL_AUTOCOMMIT_ON); - if (!SQL_SUCCEEDED(dberr)) { - throw ConnectionError(dberr, SQL_HANDLE_DBC, conn, "Set default auto commit"); - } - char info[1024]; - dberr = SQLGetInfo(conn, SQL_DRIVER_NAME, (SQLCHAR*)info, sizeof(info), NULL); - if (!SQL_SUCCEEDED(dberr)) { - throw ConnectionError(dberr, SQL_HANDLE_DBC, conn, "Get info"); - } - // Apply known DB specific tweaks - if (strstr(info, "myodbc") != NULL) { - thinkDelStyle = DB::BulkDeleteUsingUsingAlias; - thinkUpdStyle = DB::BulkUpdateUsingJoin; - } -} - -ODBC::Connection::Connection(const std::string & s) : - env(0), - conn(0), - thinkDelStyle(DB::BulkDeleteUsingUsing), - thinkUpdStyle(DB::BulkUpdateUsingFromSrc), - txDepth(0), - txAborted(false) -{ - connectPre(); - RETCODE dberr = SQLDriverConnect(conn, NULL, (SQLCHAR*)s.c_str(), s.length(), NULL, 0, NULL, SQL_DRIVER_NOPROMPT); - if (!SQL_SUCCEEDED(dberr)) { - throw ConnectionError(dberr, SQL_HANDLE_DBC, conn, "Connect"); - } - connectPost(); -} - -ODBC::Connection::~Connection() -{ - if (conn) { - if (!SQL_SUCCEEDED(SQLDisconnect(conn))) { - syslog(LOG_WARNING, "%s: Disconnect error", __FUNCTION__); - } - if (!SQL_SUCCEEDED(SQLFreeHandle(SQL_HANDLE_DBC, conn))) { - syslog(LOG_WARNING, "%s: Free connection handle error", __FUNCTION__); - } - } - if (env) { - if (!SQL_SUCCEEDED(SQLFreeHandle(SQL_HANDLE_ENV, env))) { - syslog(LOG_WARNING, "%s: Free connection handle error", __FUNCTION__); - } - } -} - -void -ODBC::Connection::finish() const -{ - if (txDepth != 0) { - rollbackTx(); - throw Error("Transaction still open"); - } -} - -int -ODBC::Connection::beginTx() const -{ - if (txDepth == 0) { - SQLRETURN dberr = SQLSetConnectOption(conn, SQL_ATTR_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF); - if (!SQL_SUCCEEDED(dberr)) { - throw Error(dberr, SQL_HANDLE_DBC, conn, "Set default auto commit"); - } - } - txDepth += 1; - return txDepth; -} - -int -ODBC::Connection::commitTx() const -{ - if (txDepth > 0) { - if (txAborted) { - return rollbackTx(); - } - txDepth -= 1; - if (txDepth == 0) { - SQLRETURN dberr = SQLEndTran(SQL_HANDLE_DBC, conn, SQL_COMMIT); - if (!SQL_SUCCEEDED(dberr)) { - throw Error(dberr, SQL_HANDLE_DBC, conn, "SQLEndTran (SQL_COMMIT)"); - } - dberr = SQLSetConnectOption(conn, SQL_ATTR_AUTOCOMMIT, SQL_AUTOCOMMIT_ON); - if (!SQL_SUCCEEDED(dberr)) { - throw Error(dberr, SQL_HANDLE_DBC, conn, "Enable auto commit"); - } - txAborted = false; - } - return txDepth; - } - throw Error("Attempt to commit none existant transaction"); -} - -int -ODBC::Connection::rollbackTx() const -{ - if (txDepth > 0) { - txDepth -= 1; - if (txDepth == 0) { - SQLRETURN dberr = SQLEndTran(SQL_HANDLE_DBC, conn, SQL_ROLLBACK); - if (!SQL_SUCCEEDED(dberr)) { - throw Error(dberr, SQL_HANDLE_DBC, conn, "SQLEndTran (SQL_ROLLBACK)"); - } - dberr = SQLSetConnectOption(conn, SQL_ATTR_AUTOCOMMIT, SQL_AUTOCOMMIT_ON); - if (!SQL_SUCCEEDED(dberr)) { - throw Error(dberr, SQL_HANDLE_DBC, conn, "Enable auto commit"); - } - txAborted = false; - } - return txDepth; - } - throw Error("Attempt to rollback none existant transaction"); -} - -void -ODBC::Connection::abortTx() const -{ - txAborted = true; -} - -bool -ODBC::Connection::txIsAborted() const -{ - return txAborted; -} - -bool -ODBC::Connection::inTx() const -{ - return (txDepth > 0); -} - -DB::BulkDeleteStyle -ODBC::Connection::bulkDeleteStyle() const -{ - return thinkDelStyle; -} - -DB::BulkUpdateStyle -ODBC::Connection::bulkUpdateStyle() const -{ - return thinkUpdStyle; -} - -DB::SelectCommand * -ODBC::Connection::newSelectCommand(const std::string & sql) const -{ - return new ODBC::SelectCommand(*this, sql); -} - -DB::ModifyCommand * -ODBC::Connection::newModifyCommand(const std::string & sql) const -{ - return new ODBC::ModifyCommand(*this, sql); -} - -std::string -ODBC::Connection::getAttrStr(SQLINTEGER attr) const -{ - std::string rtn; - rtn.resize(BUFSIZ); - SQLINTEGER size = 0; - SQLINTEGER dberr = SQLGetConnectAttr(conn, attr, (unsigned char *)rtn.c_str(), BUFSIZ, &size); - if (!SQL_SUCCEEDED(dberr)) { - throw ODBC::Error(dberr, SQL_HANDLE_DBC, conn, "ODBC::Connection::getAttrStr SQLGetConnectAttr"); - } - rtn.resize(size); - return rtn; -} - -SQLINTEGER -ODBC::Connection::getAttrInt(SQLINTEGER attr) const -{ - SQLINTEGER result; - SQLINTEGER dberr = SQLGetConnectAttr(conn, attr, &result, sizeof(result), 0); - if (!SQL_SUCCEEDED(dberr)) { - throw ODBC::Error(dberr, SQL_HANDLE_DBC, conn, "ODBC::Connection::getAttrInt SQLGetConnectAttr"); - } - return result; -} - -void -ODBC::Connection::ping() const -{ - SQLINTEGER dead = getAttrInt(SQL_ATTR_CONNECTION_DEAD); - if (dead != SQL_CD_FALSE) { - throw ODBC::Error("Connection is dead"); - } -} - -ODBC::ConnectionError::ConnectionError(RETCODE err, SQLSMALLINT handletype, SQLHANDLE handle, char const * stage) : - ODBC::Error(err, handletype, handle, stage), - DB::ConnectionError() -{ -} - -ODBC::ConnectionError::ConnectionError(const ConnectionError & e) : - ODBC::Error(strdup(e.what())), - DB::ConnectionError(e.FailureTime) -{ -} - -void ODBC::Connection::beginBulkUpload(const char *, const char *) const -{ - throw std::runtime_error("Not implemented"); -} -void ODBC::Connection::endBulkUpload(const char *) const -{ - throw std::runtime_error("Not implemented"); -} -size_t ODBC::Connection::bulkUploadData(const char *, size_t) const -{ - throw std::runtime_error("Not implemented"); -} - diff --git a/libodbcpp/connection.h b/libodbcpp/connection.h deleted file mode 100644 index bc05b63..0000000 --- a/libodbcpp/connection.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef ODBC_CONNECTION_H -#define ODBC_CONNECTION_H - -#include -#include -#include "dsn.h" -#include "error.h" -#include - -namespace ODBC { - class Connection : public DB::Connection { - public: - Connection(const DSN& d); - Connection(const std::string & str); - ~Connection(); - SQLHENV env; - SQLHDBC conn; - - void finish() const; - int beginTx() const; - int commitTx() const; - int rollbackTx() const; - void abortTx() const; - bool txIsAborted() const; - bool inTx() const; - void ping() const; - std::string getAttrStr(SQLINTEGER) const; - SQLINTEGER getAttrInt(SQLINTEGER) const; - DB::BulkDeleteStyle bulkDeleteStyle() const; - DB::BulkUpdateStyle bulkUpdateStyle() const; - - DB::SelectCommand * newSelectCommand(const std::string & sql) const; - DB::ModifyCommand * newModifyCommand(const std::string & sql) const; - - void beginBulkUpload(const char *, const char *) const; - void endBulkUpload(const char *) const; - size_t bulkUploadData(const char *, size_t) const; - - private: - DB::BulkDeleteStyle thinkDelStyle; - DB::BulkUpdateStyle thinkUpdStyle; - - void connectPre(); - void connectPost(); - mutable unsigned int txDepth; - mutable bool txAborted; - }; - class ConnectionError : public DB::ConnectionError, public virtual Error { - public: - ConnectionError(RETCODE err, SQLSMALLINT handletype, SQLHANDLE handle, char const * stage); - ConnectionError(const ConnectionError &); - }; -} - -#endif - diff --git a/libodbcpp/dsn.cpp b/libodbcpp/dsn.cpp deleted file mode 100644 index 337319b..0000000 --- a/libodbcpp/dsn.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "dsn.h" - -ODBC::DSN::DSN(const std::string & d, const std::string & u, const std::string & p) : - dsn(d), - username(u), - password(p) -{ -} - -ODBC::DSN::~DSN() -{ -} - diff --git a/libodbcpp/dsn.h b/libodbcpp/dsn.h deleted file mode 100644 index 6be7e3b..0000000 --- a/libodbcpp/dsn.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef DSN_H -#define DSN_H - -#include - -namespace ODBC { - class DSN { - public: - DSN(const std::string &, const std::string &, const std::string &); - virtual ~DSN(); - const std::string dsn; // DSN name for odbc.ini - const std::string username; // User name - const std::string password; // Password - }; -} - -#endif - diff --git a/libodbcpp/error.cpp b/libodbcpp/error.cpp deleted file mode 100644 index 7707401..0000000 --- a/libodbcpp/error.cpp +++ /dev/null @@ -1,86 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include "error.h" - -static -void -odbc_verror(RETCODE err, SQLSMALLINT handletype, SQLHANDLE handle, char const * action, char ** msg) -{ - SQLCHAR sqlstatus[6]; - SQLINTEGER sqlerr; - SQLCHAR sqlerrmsg[12800]; - - SQLRETURN rc = SQLGetDiagRec(handletype, handle, 1, sqlstatus, &sqlerr, sqlerrmsg, - sizeof(sqlerrmsg), NULL); - switch (rc) { - case SQL_SUCCESS: - case SQL_SUCCESS_WITH_INFO: - if (msg) { - if (asprintf(msg, "%d: %d: %5.5s: \"%s\" while attempting to %s", - err, (int)sqlerr, sqlstatus, sqlerrmsg, action) < 1) { - *msg = NULL; - } - } - syslog(LOG_WARNING, "%s: %d: %d: %5.5s: \"%s\" while attempting to %s", - __FUNCTION__, err, (int)sqlerr, sqlstatus, sqlerrmsg, action); - break; - - case SQL_INVALID_HANDLE: - if (msg) { - if (asprintf(msg, "(%d) Invalid handle passed into function trying to %s.", - err, action) < 1) { - *msg = NULL; - } - } - syslog(LOG_ERR, "%s: (%d) Invalid handle passed into function trying to %s.", - __FUNCTION__, err, action); - break; - - case SQL_NO_DATA: - if (msg) { - if (asprintf(msg, "(%d) No error data available for record trying to %s.", - err, action) < 1) { - *msg = NULL; - } - } - syslog(LOG_ERR, "%s: (%d) No error data available for record trying to %s.", - __FUNCTION__, err, action); - break; - - case SQL_ERROR: - default: - syslog(LOG_ERR, "%s: Unexpected error!!", __FUNCTION__); - break; - } -} - -ODBC::Error::Error(RETCODE err, SQLSMALLINT handletype, SQLHANDLE handle, char const * action) -{ - odbc_verror(err, handletype, handle, action, &msg); -} - -ODBC::Error::Error(char const * action) -{ - syslog(LOG_ERR, "%s", action); - msg = strdup(action); -} - -ODBC::Error::Error(char * m) : msg(m) -{ -} - -ODBC::Error::~Error() throw() -{ - free(msg); -} - -const char * -ODBC::Error::what() const throw() -{ - return msg; -} - diff --git a/libodbcpp/error.h b/libodbcpp/error.h deleted file mode 100644 index 0348980..0000000 --- a/libodbcpp/error.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef ODBC_ERROR_H -#define ODBC_ERROR_H - -#include -#include -#include -#include - -namespace ODBC { - class Error : public DB::Error { - public: - Error(RETCODE err, SQLSMALLINT handletype, SQLHANDLE handle, char const * action); - Error(char const * action); - ~Error() throw(); - - const char * what() const throw(); - protected: - Error(char * msg); - private: - char * msg; - }; -} - -#endif diff --git a/libodbcpp/mock.cpp b/libodbcpp/mock.cpp deleted file mode 100644 index 58d5afd..0000000 --- a/libodbcpp/mock.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include "connection.h" -#include "mock.h" -#include - -namespace ODBC { - -Mock::Mock(const std::string & masterdb, const std::string & name, const std::vector & ss) : - MockServerDatabase(masterdb, name, "odbc") -{ - CreateNewDatabase(); - PlaySchemaScripts(ss); -} - -DB::Connection * -Mock::openConnection() const -{ - return new Connection(stringbf("Driver=postgresql;Database=%s;uid=postgres;servername=/run/postgresql", testDbName)); -} - -Mock::~Mock() -{ - DropDatabase(); -} - -void Mock::DropDatabase() const -{ - master->execute("SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = '" + testDbName + "'"); - MockServerDatabase::DropDatabase(); -} - -} - diff --git a/libodbcpp/mock.h b/libodbcpp/mock.h deleted file mode 100644 index d2bcbfe..0000000 --- a/libodbcpp/mock.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef MOCKODBCDATASOURCE_H -#define MOCKODBCDATASOURCE_H - -#include -#include -#include - -namespace ODBC { - -class DLL_PUBLIC Mock : public DB::MockServerDatabase { - public: - Mock(const std::string & master, const std::string & name, const std::vector & ss); - ~Mock(); - - protected: - void DropDatabase() const override; - - private: - DB::Connection * openConnection() const override; -}; - -} - -#endif - diff --git a/libodbcpp/modifycommand.cpp b/libodbcpp/modifycommand.cpp deleted file mode 100644 index 7a39be5..0000000 --- a/libodbcpp/modifycommand.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include "modifycommand.h" -#include "error.h" - -ODBC::ModifyCommand::ModifyCommand(const ODBC::Connection & c, const std::string & sql) : - DB::Command(sql), - ODBC::Command(c, sql), - DB::ModifyCommand(sql) -{ -} - -ODBC::ModifyCommand::~ModifyCommand() -{ -} - -unsigned int -ODBC::ModifyCommand::execute(bool anc) -{ - if (connection.txIsAborted()) { - throw Error("Transaction has been aborted, not issuing any more commands"); - } - RETCODE rc = SQLExecute(hStmt); - if (!SQL_SUCCEEDED(rc)) { - if (rc != SQL_NO_DATA || !anc) { - connection.abortTx(); - throw Error(rc, SQL_HANDLE_STMT, hStmt, "ODBC::ModifyCommand::execute SQLExecute"); - } - } - SQLLEN rows; - rc = SQLRowCount(hStmt, &rows); - if (!SQL_SUCCEEDED(rc)) { - connection.abortTx(); - throw Error(rc, SQL_HANDLE_STMT, hStmt, "ODBC::ModifyCommand::execute SQLRowCount"); - } - if (rows > 0 || anc) { - return rows; - } - connection.abortTx(); - throw Error("No rows affected"); -} - diff --git a/libodbcpp/modifycommand.h b/libodbcpp/modifycommand.h deleted file mode 100644 index 24fb960..0000000 --- a/libodbcpp/modifycommand.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef ODBC_MODIFYCOMMAND_H -#define ODBC_MODIFYCOMMAND_H - -#include -#include "command.h" - -namespace ODBC { - class ModifyCommand : public Command, public DB::ModifyCommand { - public: - ModifyCommand(const Connection &, const std::string & sql); - ~ModifyCommand(); - // Execute the command and return effected row count - unsigned int execute(bool allowNoChange = true); - }; -} - -#endif - diff --git a/libodbcpp/odbc-bind.cpp b/libodbcpp/odbc-bind.cpp new file mode 100644 index 0000000..1575fd0 --- /dev/null +++ b/libodbcpp/odbc-bind.cpp @@ -0,0 +1,11 @@ +#include "odbc-bind.h" + +ODBC::Bind::Bind() +{ +} + +ODBC::Bind::~Bind() +{ +} + + diff --git a/libodbcpp/odbc-bind.h b/libodbcpp/odbc-bind.h new file mode 100644 index 0000000..356723b --- /dev/null +++ b/libodbcpp/odbc-bind.h @@ -0,0 +1,21 @@ +#ifndef ODBC_BIND_H +#define ODBC_BIND_H + +#include +#include + +namespace ODBC { + class Bind { + public: + Bind(); + virtual ~Bind() = 0; + + virtual SQLSMALLINT ctype() const = 0; // The C type ID + virtual SQLULEN size() const = 0; // The size of the data + protected: + mutable SQLLEN bindLen; // How much data the driver wants to store + }; +} + +#endif + diff --git a/libodbcpp/odbc-client.h b/libodbcpp/odbc-client.h new file mode 100644 index 0000000..3fb94aa --- /dev/null +++ b/libodbcpp/odbc-client.h @@ -0,0 +1,7 @@ +#include "odbc-column.h" +#include "odbc-command.h" +#include "odbc-connection.h" +#include "odbc-dsn.h" +#include "odbc-modifycommand.h" +#include "odbc-param.h" +#include "odbc-selectcommand.h" diff --git a/libodbcpp/odbc-column.cpp b/libodbcpp/odbc-column.cpp new file mode 100644 index 0000000..20c68f0 --- /dev/null +++ b/libodbcpp/odbc-column.cpp @@ -0,0 +1,106 @@ +#include +#include +#include +#include "odbc-column.h" +#include "odbc-command.h" +#include "odbc-selectcommand.h" +#include "odbc-error.h" + +ODBC::Column::Column(SelectCommand * sc, const Glib::ustring & s, unsigned int i) : + DB::Column(s, i), + selectCmd(sc) +{ + bindLen = 0; +} + +ODBC::Column::~Column() +{ +} + +bool +ODBC::Column::resize() +{ + return false; +} + +bool +ODBC::CharArrayColumn::resize() +{ + if (bindLen >= SQLLEN(data.size())) { + data.resize(bindLen + 1); + Column::bind(); + if (paramCmd) { + paramBound = false; + Param::bind(); + } + return true; + } + return false; +} + +bool +ODBC::Column::isNull() const +{ + return (bindLen == SQL_NULL_DATA); +} + +void +ODBC::Column::rebind(DB::Command * cmd, unsigned int idx) const +{ + meAsAParam()->paramCmd = dynamic_cast(cmd); + meAsAParam()->paramIdx = idx; + meAsAParam()->bind(); +} + +void +ODBC::Column::bind() +{ + RETCODE rc = SQLBindCol(selectCmd->hStmt, colNo + 1, ctype(), rwDataAddress(), size(), &bindLen); + if (!SQL_SUCCEEDED(rc)) { + throw Error(rc, SQL_HANDLE_STMT, selectCmd->hStmt, "ODBC::Column::bind"); + } +} + +ODBC::TimeStampColumn::operator boost::posix_time::ptime() const +{ + return boost::posix_time::ptime( + boost::gregorian::date(data.year, data.month, data.day), + boost::posix_time::time_duration(data.hour, data.minute, data.second, data.fraction)); +} +ODBC::IntervalColumn::operator boost::posix_time::time_duration() const +{ + auto dur = boost::posix_time::time_duration( + (24 * data.intval.day_second.day) + data.intval.day_second.hour, + data.intval.day_second.minute, data.intval.day_second.second, data.intval.day_second.fraction); + return (data.interval_sign ? -dur : dur); +} +void +ODBC::SignedIntegerColumn::apply(DB::HandleField & h) const +{ + if (isNull()) return h.null(); + h.integer(data); +} +void +ODBC::FloatingPointColumn::apply(DB::HandleField & h) const +{ + if (isNull()) return h.null(); + h.floatingpoint(data); +} +void +ODBC::CharArrayColumn::apply(DB::HandleField & h) const +{ + if (isNull()) return h.null(); + h.string(&data.front(), bindLen); +} +void +ODBC::TimeStampColumn::apply(DB::HandleField & h) const +{ + if (isNull()) return h.null(); + h.timestamp(*this); +} +void +ODBC::IntervalColumn::apply(DB::HandleField & h) const +{ + if (isNull()) return h.null(); + h.interval(*this); +} diff --git a/libodbcpp/odbc-column.h b/libodbcpp/odbc-column.h new file mode 100644 index 0000000..d80ec63 --- /dev/null +++ b/libodbcpp/odbc-column.h @@ -0,0 +1,131 @@ +#ifndef ODBC_COLUMN_H +#define ODBC_COLUMN_H + +#include +#include +#include +#include +#include "odbc-bind.h" +#include "odbc-param.h" + +namespace ODBC { + class SelectCommand; + class Column : public virtual Bind, public virtual DB::Column { + public: + Column(SelectCommand *, const Glib::ustring & s, unsigned int i); + virtual ~Column() = 0; + void bind(); + virtual void * rwDataAddress() = 0; + void rebind(DB::Command *, unsigned int idx) const; + virtual bool resize(); + + virtual operator int () const { throw std::bad_cast(); } + virtual operator long () const { throw std::bad_cast(); } + virtual operator long long () const { throw std::bad_cast(); } + virtual operator unsigned int () const { throw std::bad_cast(); } + virtual operator unsigned long () const { throw std::bad_cast(); } + virtual operator unsigned long long () const { throw std::bad_cast(); } + + virtual operator double () const { throw std::bad_cast(); } + virtual operator float () const { throw std::bad_cast(); } + + virtual operator std::string () const { throw std::bad_cast(); } + virtual operator Glib::ustring () const { throw std::bad_cast(); } + + virtual operator struct tm () const { throw std::bad_cast(); } + virtual operator SQL_TIMESTAMP_STRUCT () const { throw std::bad_cast(); } + + bool isNull() const; + virtual void apply(DB::HandleField &) const = 0; + + const SelectCommand * selectCmd; + protected: + virtual const Param * meAsAParam() const = 0; + }; + class CharArrayColumn : public Column, public Param { + public: + typedef std::vector CharArray; + CharArrayColumn(SelectCommand * sc, const Glib::ustring & n, unsigned int i, SQLULEN sizeHint) : + DB::Column(n, i), + Column(sc, n, i) + { + data.resize(std::max(sizeHint, 64) + 1); + } + virtual SQLSMALLINT ctype() const { return SQL_C_CHAR; } + virtual SQLSMALLINT stype() const { return SQL_CHAR; } + virtual SQLULEN size() const { return data.size(); } + virtual SQLINTEGER dp() const { return 0; } + virtual const void * dataAddress() const { return &data.front(); } + virtual void * rwDataAddress() { return &data.front(); } + void operator=(const Glib::ustring & d); + bool resize(); + virtual operator std::string () const { return std::string(&data.front(), bindLen); } + virtual operator Glib::ustring () const { return std::string(&data.front(), bindLen); } + virtual void apply(DB::HandleField &) const; + protected: + virtual const Param * meAsAParam() const { return this; } + CharArray data; + }; + class SignedIntegerColumn : public Column, public SignedIntegerParam { + public: + SignedIntegerColumn(SelectCommand * sc, const Glib::ustring & n, unsigned int i) : + DB::Column(n, i), + Column(sc, n, i) { } + virtual SQLSMALLINT ctype() const { return SignedIntegerParam::ctype(); } + virtual SQLULEN size() const { return SignedIntegerParam::size(); } + virtual void * rwDataAddress() { return &data; } + virtual operator int () const { return data; } + virtual operator long () const { return data; } + virtual operator long long () const { return data; } + virtual const Param * meAsAParam() const { return this; } + virtual void apply(DB::HandleField &) const; + }; +#ifdef COMPLETENESS + class UnsignedIntegerColumn : public Column, public UnsignedIntegerParam { + public: + UnsignedIntegerColumn(SelectCommand * sc, const Glib::ustring & n, unsigned int i) : + Column(sc, n, i) { } + virtual const Param * meAsAParam() const { return this; } + }; +#endif + class FloatingPointColumn : public Column, public FloatingPointParam { + public: + FloatingPointColumn(SelectCommand * sc, const Glib::ustring & n, unsigned int i) : + DB::Column(n, i), + Column(sc, n, i) { } + virtual SQLSMALLINT ctype() const { return FloatingPointParam::ctype(); } + virtual SQLULEN size() const { return FloatingPointParam::size(); } + virtual void * rwDataAddress() { return &data; } + virtual operator double () const { return data; } + virtual operator float () const { return data; } + virtual const Param * meAsAParam() const { return this; } + virtual void apply(DB::HandleField &) const; + }; + class IntervalColumn : public Column, public IntervalParam { + public: + IntervalColumn(SelectCommand * sc, const Glib::ustring & n, unsigned int i) : + DB::Column(n, i), + Column(sc, n, i) { } + virtual SQLSMALLINT ctype() const { return IntervalParam::ctype(); } + virtual SQLULEN size() const { return IntervalParam::size(); } + virtual void * rwDataAddress() { return &data; } + virtual operator boost::posix_time::time_duration () const; + virtual const Param * meAsAParam() const { return this; } + virtual void apply(DB::HandleField &) const; + }; + class TimeStampColumn : public Column, public TimeStampParam { + public: + TimeStampColumn(SelectCommand * sc, const Glib::ustring & n, unsigned int i) : + DB::Column(n, i), + Column(sc, n, i) { } + virtual SQLSMALLINT ctype() const { return TimeStampParam::ctype(); } + virtual SQLULEN size() const { return TimeStampParam::size(); } + virtual void * rwDataAddress() { return &data; } + virtual operator boost::posix_time::ptime () const; + virtual const Param * meAsAParam() const { return this; } + virtual void apply(DB::HandleField &) const; + }; +} + +#endif + diff --git a/libodbcpp/odbc-command.cpp b/libodbcpp/odbc-command.cpp new file mode 100644 index 0000000..d96234d --- /dev/null +++ b/libodbcpp/odbc-command.cpp @@ -0,0 +1,40 @@ +#include "odbc-command.h" +#include "odbc-error.h" +#include "odbc-param.h" +#include + +ODBC::Command::Command(const Connection & c, const std::string & s) : + DB::Command(s), + connection(c) +{ + RETCODE rc = SQLAllocHandle(SQL_HANDLE_STMT, c.conn, &hStmt); + if (!SQL_SUCCEEDED(rc)) { + throw Error(rc, SQL_HANDLE_STMT, hStmt, "Allocate statement handle"); + } + rc = SQLSetStmtAttr(hStmt, SQL_ATTR_CURSOR_TYPE, (SQLPOINTER)SQL_CURSOR_DYNAMIC, 0); + if (!SQL_SUCCEEDED(rc)) { + throw ConnectionError(rc, SQL_HANDLE_STMT, hStmt, "Set scrollable cursor"); + } + rc = SQLPrepare(hStmt, (SQLCHAR*)sql.c_str(), sql.length()); + if (!SQL_SUCCEEDED(rc)) { + SQLFreeHandle(SQL_HANDLE_STMT, hStmt); + throw Error(rc, SQL_HANDLE_STMT, hStmt, "Prepare statement"); + } + SQLSMALLINT pcount; + rc = SQLNumParams(hStmt, &pcount); + if (!SQL_SUCCEEDED(rc)) { + SQLFreeHandle(SQL_HANDLE_STMT, hStmt); + throw Error(rc, SQL_HANDLE_STMT, hStmt, "Parameter count"); + } + params.resize(pcount); +} + +ODBC::Command::~Command() +{ + for (Params::iterator i = params.begin(); i != params.end(); ++i) { + if (*i) { + delete *i; + } + } +} + diff --git a/libodbcpp/odbc-command.h b/libodbcpp/odbc-command.h new file mode 100644 index 0000000..d7173e3 --- /dev/null +++ b/libodbcpp/odbc-command.h @@ -0,0 +1,52 @@ +#ifndef ODBC_COMMAND_H +#define ODBC_COMMAND_H + +#include +#include +#include "odbc-connection.h" +#include + +namespace ODBC { + class Param; + class Command : public virtual DB::Command { + typedef std::vector Params; + public: + Command(const Connection &, const std::string & sql); + virtual ~Command() = 0; + + void bindParamI(unsigned int i, int val); + void bindParamI(unsigned int i, long val); + void bindParamI(unsigned int i, long long val); + void bindParamI(unsigned int i, unsigned int val); + void bindParamI(unsigned int i, unsigned long int val); + void bindParamI(unsigned int i, unsigned long long int val); + + void bindParamB(unsigned int i, bool val); + + void bindParamF(unsigned int i, double val); + void bindParamF(unsigned int i, float val); + + void bindParamS(unsigned int i, const Glib::ustring &); + + void bindParamT(unsigned int i, const boost::posix_time::time_duration &); + void bindParamT(unsigned int i, const boost::posix_time::ptime &); + + void bindNull(unsigned int i); + + protected: + friend class Param; + friend class Column; + SQLHSTMT hStmt; + const Connection& connection; + private: + Params params; + + template + ParamType * + makeParam(unsigned int idx); + }; + +} + +#endif + diff --git a/libodbcpp/odbc-connection.cpp b/libodbcpp/odbc-connection.cpp new file mode 100644 index 0000000..a6fa2bd --- /dev/null +++ b/libodbcpp/odbc-connection.cpp @@ -0,0 +1,273 @@ +#include +#include +#include +#include +#include +#include "odbc-connection.h" +#include "odbc-selectcommand.h" +#include "odbc-modifycommand.h" +#include "error.h" + +NAMEDFACTORY("odbc", ODBC::Connection, DB::ConnectionFactory); + +ODBC::Connection::Connection(const DSN& d) : + env(0), + conn(0), + thinkDelStyle(DB::BulkDeleteUsingUsing), + thinkUpdStyle(DB::BulkUpdateUsingFromSrc), + txDepth(0), + txAborted(false) +{ + connectPre(); + RETCODE dberr = SQLConnect(conn, (SQLCHAR*)d.dsn.c_str(), SQL_NTS, + (SQLCHAR*)d.username.c_str(), SQL_NTS, (SQLCHAR*)d.password.c_str(), SQL_NTS); + if (!SQL_SUCCEEDED(dberr)) { + throw ConnectionError(dberr, SQL_HANDLE_DBC, conn, "Connect"); + } + connectPost(); +} + +void +ODBC::Connection::connectPre() +{ + SQLRETURN dberr = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env); + if (!SQL_SUCCEEDED(dberr)) { + throw ConnectionError(dberr, SQL_HANDLE_ENV, env, "Allocate handle"); + } + + dberr = SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0); + if (!SQL_SUCCEEDED(dberr)) { + throw ConnectionError(dberr, SQL_HANDLE_ENV, env, "Set ODBC version"); + } + + dberr = SQLAllocHandle(SQL_HANDLE_DBC, env, &conn); + if (!SQL_SUCCEEDED(dberr)) { + throw ConnectionError(dberr, SQL_HANDLE_ENV, env, "Allocate DBC handle"); + } + + dberr = SQLSetConnectAttr(conn, SQL_LOGIN_TIMEOUT, (SQLPOINTER *)5, 0); + if (!SQL_SUCCEEDED(dberr)) { + throw ConnectionError(dberr, SQL_HANDLE_ENV, env, "Set connection attributes"); + } +} + +void +ODBC::Connection::connectPost() +{ + RETCODE dberr = SQLSetConnectOption(conn, SQL_ATTR_AUTOCOMMIT, SQL_AUTOCOMMIT_ON); + if (!SQL_SUCCEEDED(dberr)) { + throw ConnectionError(dberr, SQL_HANDLE_DBC, conn, "Set default auto commit"); + } + char info[1024]; + dberr = SQLGetInfo(conn, SQL_DRIVER_NAME, (SQLCHAR*)info, sizeof(info), NULL); + if (!SQL_SUCCEEDED(dberr)) { + throw ConnectionError(dberr, SQL_HANDLE_DBC, conn, "Get info"); + } + // Apply known DB specific tweaks + if (strstr(info, "myodbc") != NULL) { + thinkDelStyle = DB::BulkDeleteUsingUsingAlias; + thinkUpdStyle = DB::BulkUpdateUsingJoin; + } +} + +ODBC::Connection::Connection(const std::string & s) : + env(0), + conn(0), + thinkDelStyle(DB::BulkDeleteUsingUsing), + thinkUpdStyle(DB::BulkUpdateUsingFromSrc), + txDepth(0), + txAborted(false) +{ + connectPre(); + RETCODE dberr = SQLDriverConnect(conn, NULL, (SQLCHAR*)s.c_str(), s.length(), NULL, 0, NULL, SQL_DRIVER_NOPROMPT); + if (!SQL_SUCCEEDED(dberr)) { + throw ConnectionError(dberr, SQL_HANDLE_DBC, conn, "Connect"); + } + connectPost(); +} + +ODBC::Connection::~Connection() +{ + if (conn) { + if (!SQL_SUCCEEDED(SQLDisconnect(conn))) { + syslog(LOG_WARNING, "%s: Disconnect error", __FUNCTION__); + } + if (!SQL_SUCCEEDED(SQLFreeHandle(SQL_HANDLE_DBC, conn))) { + syslog(LOG_WARNING, "%s: Free connection handle error", __FUNCTION__); + } + } + if (env) { + if (!SQL_SUCCEEDED(SQLFreeHandle(SQL_HANDLE_ENV, env))) { + syslog(LOG_WARNING, "%s: Free connection handle error", __FUNCTION__); + } + } +} + +void +ODBC::Connection::finish() const +{ + if (txDepth != 0) { + rollbackTx(); + throw Error("Transaction still open"); + } +} + +int +ODBC::Connection::beginTx() const +{ + if (txDepth == 0) { + SQLRETURN dberr = SQLSetConnectOption(conn, SQL_ATTR_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF); + if (!SQL_SUCCEEDED(dberr)) { + throw Error(dberr, SQL_HANDLE_DBC, conn, "Set default auto commit"); + } + } + txDepth += 1; + return txDepth; +} + +int +ODBC::Connection::commitTx() const +{ + if (txDepth > 0) { + if (txAborted) { + return rollbackTx(); + } + txDepth -= 1; + if (txDepth == 0) { + SQLRETURN dberr = SQLEndTran(SQL_HANDLE_DBC, conn, SQL_COMMIT); + if (!SQL_SUCCEEDED(dberr)) { + throw Error(dberr, SQL_HANDLE_DBC, conn, "SQLEndTran (SQL_COMMIT)"); + } + dberr = SQLSetConnectOption(conn, SQL_ATTR_AUTOCOMMIT, SQL_AUTOCOMMIT_ON); + if (!SQL_SUCCEEDED(dberr)) { + throw Error(dberr, SQL_HANDLE_DBC, conn, "Enable auto commit"); + } + txAborted = false; + } + return txDepth; + } + throw Error("Attempt to commit none existant transaction"); +} + +int +ODBC::Connection::rollbackTx() const +{ + if (txDepth > 0) { + txDepth -= 1; + if (txDepth == 0) { + SQLRETURN dberr = SQLEndTran(SQL_HANDLE_DBC, conn, SQL_ROLLBACK); + if (!SQL_SUCCEEDED(dberr)) { + throw Error(dberr, SQL_HANDLE_DBC, conn, "SQLEndTran (SQL_ROLLBACK)"); + } + dberr = SQLSetConnectOption(conn, SQL_ATTR_AUTOCOMMIT, SQL_AUTOCOMMIT_ON); + if (!SQL_SUCCEEDED(dberr)) { + throw Error(dberr, SQL_HANDLE_DBC, conn, "Enable auto commit"); + } + txAborted = false; + } + return txDepth; + } + throw Error("Attempt to rollback none existant transaction"); +} + +void +ODBC::Connection::abortTx() const +{ + txAborted = true; +} + +bool +ODBC::Connection::txIsAborted() const +{ + return txAborted; +} + +bool +ODBC::Connection::inTx() const +{ + return (txDepth > 0); +} + +DB::BulkDeleteStyle +ODBC::Connection::bulkDeleteStyle() const +{ + return thinkDelStyle; +} + +DB::BulkUpdateStyle +ODBC::Connection::bulkUpdateStyle() const +{ + return thinkUpdStyle; +} + +DB::SelectCommand * +ODBC::Connection::newSelectCommand(const std::string & sql) const +{ + return new ODBC::SelectCommand(*this, sql); +} + +DB::ModifyCommand * +ODBC::Connection::newModifyCommand(const std::string & sql) const +{ + return new ODBC::ModifyCommand(*this, sql); +} + +std::string +ODBC::Connection::getAttrStr(SQLINTEGER attr) const +{ + std::string rtn; + rtn.resize(BUFSIZ); + SQLINTEGER size = 0; + SQLINTEGER dberr = SQLGetConnectAttr(conn, attr, (unsigned char *)rtn.c_str(), BUFSIZ, &size); + if (!SQL_SUCCEEDED(dberr)) { + throw ODBC::Error(dberr, SQL_HANDLE_DBC, conn, "ODBC::Connection::getAttrStr SQLGetConnectAttr"); + } + rtn.resize(size); + return rtn; +} + +SQLINTEGER +ODBC::Connection::getAttrInt(SQLINTEGER attr) const +{ + SQLINTEGER result; + SQLINTEGER dberr = SQLGetConnectAttr(conn, attr, &result, sizeof(result), 0); + if (!SQL_SUCCEEDED(dberr)) { + throw ODBC::Error(dberr, SQL_HANDLE_DBC, conn, "ODBC::Connection::getAttrInt SQLGetConnectAttr"); + } + return result; +} + +void +ODBC::Connection::ping() const +{ + SQLINTEGER dead = getAttrInt(SQL_ATTR_CONNECTION_DEAD); + if (dead != SQL_CD_FALSE) { + throw ODBC::Error("Connection is dead"); + } +} + +ODBC::ConnectionError::ConnectionError(RETCODE err, SQLSMALLINT handletype, SQLHANDLE handle, char const * stage) : + ODBC::Error(err, handletype, handle, stage), + DB::ConnectionError() +{ +} + +ODBC::ConnectionError::ConnectionError(const ConnectionError & e) : + ODBC::Error(strdup(e.what())), + DB::ConnectionError(e.FailureTime) +{ +} + +void ODBC::Connection::beginBulkUpload(const char *, const char *) const +{ + throw std::runtime_error("Not implemented"); +} +void ODBC::Connection::endBulkUpload(const char *) const +{ + throw std::runtime_error("Not implemented"); +} +size_t ODBC::Connection::bulkUploadData(const char *, size_t) const +{ + throw std::runtime_error("Not implemented"); +} + diff --git a/libodbcpp/odbc-connection.h b/libodbcpp/odbc-connection.h new file mode 100644 index 0000000..d927b70 --- /dev/null +++ b/libodbcpp/odbc-connection.h @@ -0,0 +1,56 @@ +#ifndef ODBC_CONNECTION_H +#define ODBC_CONNECTION_H + +#include +#include +#include "odbc-dsn.h" +#include "odbc-error.h" +#include + +namespace ODBC { + class Connection : public DB::Connection { + public: + Connection(const DSN& d); + Connection(const std::string & str); + ~Connection(); + SQLHENV env; + SQLHDBC conn; + + void finish() const; + int beginTx() const; + int commitTx() const; + int rollbackTx() const; + void abortTx() const; + bool txIsAborted() const; + bool inTx() const; + void ping() const; + std::string getAttrStr(SQLINTEGER) const; + SQLINTEGER getAttrInt(SQLINTEGER) const; + DB::BulkDeleteStyle bulkDeleteStyle() const; + DB::BulkUpdateStyle bulkUpdateStyle() const; + + DB::SelectCommand * newSelectCommand(const std::string & sql) const; + DB::ModifyCommand * newModifyCommand(const std::string & sql) const; + + void beginBulkUpload(const char *, const char *) const; + void endBulkUpload(const char *) const; + size_t bulkUploadData(const char *, size_t) const; + + private: + DB::BulkDeleteStyle thinkDelStyle; + DB::BulkUpdateStyle thinkUpdStyle; + + void connectPre(); + void connectPost(); + mutable unsigned int txDepth; + mutable bool txAborted; + }; + class ConnectionError : public DB::ConnectionError, public virtual Error { + public: + ConnectionError(RETCODE err, SQLSMALLINT handletype, SQLHANDLE handle, char const * stage); + ConnectionError(const ConnectionError &); + }; +} + +#endif + diff --git a/libodbcpp/odbc-dsn.cpp b/libodbcpp/odbc-dsn.cpp new file mode 100644 index 0000000..766b0ac --- /dev/null +++ b/libodbcpp/odbc-dsn.cpp @@ -0,0 +1,13 @@ +#include "odbc-dsn.h" + +ODBC::DSN::DSN(const std::string & d, const std::string & u, const std::string & p) : + dsn(d), + username(u), + password(p) +{ +} + +ODBC::DSN::~DSN() +{ +} + diff --git a/libodbcpp/odbc-dsn.h b/libodbcpp/odbc-dsn.h new file mode 100644 index 0000000..6be7e3b --- /dev/null +++ b/libodbcpp/odbc-dsn.h @@ -0,0 +1,18 @@ +#ifndef DSN_H +#define DSN_H + +#include + +namespace ODBC { + class DSN { + public: + DSN(const std::string &, const std::string &, const std::string &); + virtual ~DSN(); + const std::string dsn; // DSN name for odbc.ini + const std::string username; // User name + const std::string password; // Password + }; +} + +#endif + diff --git a/libodbcpp/odbc-error.cpp b/libodbcpp/odbc-error.cpp new file mode 100644 index 0000000..182c022 --- /dev/null +++ b/libodbcpp/odbc-error.cpp @@ -0,0 +1,86 @@ +#include +#include +#include +#include +#include +#include +#include "odbc-error.h" + +static +void +odbc_verror(RETCODE err, SQLSMALLINT handletype, SQLHANDLE handle, char const * action, char ** msg) +{ + SQLCHAR sqlstatus[6]; + SQLINTEGER sqlerr; + SQLCHAR sqlerrmsg[12800]; + + SQLRETURN rc = SQLGetDiagRec(handletype, handle, 1, sqlstatus, &sqlerr, sqlerrmsg, + sizeof(sqlerrmsg), NULL); + switch (rc) { + case SQL_SUCCESS: + case SQL_SUCCESS_WITH_INFO: + if (msg) { + if (asprintf(msg, "%d: %d: %5.5s: \"%s\" while attempting to %s", + err, (int)sqlerr, sqlstatus, sqlerrmsg, action) < 1) { + *msg = NULL; + } + } + syslog(LOG_WARNING, "%s: %d: %d: %5.5s: \"%s\" while attempting to %s", + __FUNCTION__, err, (int)sqlerr, sqlstatus, sqlerrmsg, action); + break; + + case SQL_INVALID_HANDLE: + if (msg) { + if (asprintf(msg, "(%d) Invalid handle passed into function trying to %s.", + err, action) < 1) { + *msg = NULL; + } + } + syslog(LOG_ERR, "%s: (%d) Invalid handle passed into function trying to %s.", + __FUNCTION__, err, action); + break; + + case SQL_NO_DATA: + if (msg) { + if (asprintf(msg, "(%d) No error data available for record trying to %s.", + err, action) < 1) { + *msg = NULL; + } + } + syslog(LOG_ERR, "%s: (%d) No error data available for record trying to %s.", + __FUNCTION__, err, action); + break; + + case SQL_ERROR: + default: + syslog(LOG_ERR, "%s: Unexpected error!!", __FUNCTION__); + break; + } +} + +ODBC::Error::Error(RETCODE err, SQLSMALLINT handletype, SQLHANDLE handle, char const * action) +{ + odbc_verror(err, handletype, handle, action, &msg); +} + +ODBC::Error::Error(char const * action) +{ + syslog(LOG_ERR, "%s", action); + msg = strdup(action); +} + +ODBC::Error::Error(char * m) : msg(m) +{ +} + +ODBC::Error::~Error() throw() +{ + free(msg); +} + +const char * +ODBC::Error::what() const throw() +{ + return msg; +} + diff --git a/libodbcpp/odbc-error.h b/libodbcpp/odbc-error.h new file mode 100644 index 0000000..0348980 --- /dev/null +++ b/libodbcpp/odbc-error.h @@ -0,0 +1,24 @@ +#ifndef ODBC_ERROR_H +#define ODBC_ERROR_H + +#include +#include +#include +#include + +namespace ODBC { + class Error : public DB::Error { + public: + Error(RETCODE err, SQLSMALLINT handletype, SQLHANDLE handle, char const * action); + Error(char const * action); + ~Error() throw(); + + const char * what() const throw(); + protected: + Error(char * msg); + private: + char * msg; + }; +} + +#endif diff --git a/libodbcpp/odbc-mock.cpp b/libodbcpp/odbc-mock.cpp new file mode 100644 index 0000000..71c4c56 --- /dev/null +++ b/libodbcpp/odbc-mock.cpp @@ -0,0 +1,32 @@ +#include "odbc-connection.h" +#include "odbc-mock.h" +#include + +namespace ODBC { + +Mock::Mock(const std::string & masterdb, const std::string & name, const std::vector & ss) : + MockServerDatabase(masterdb, name, "odbc") +{ + CreateNewDatabase(); + PlaySchemaScripts(ss); +} + +DB::Connection * +Mock::openConnection() const +{ + return new Connection(stringbf("Driver=postgresql;Database=%s;uid=postgres;servername=/run/postgresql", testDbName)); +} + +Mock::~Mock() +{ + DropDatabase(); +} + +void Mock::DropDatabase() const +{ + master->execute("SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = '" + testDbName + "'"); + MockServerDatabase::DropDatabase(); +} + +} + diff --git a/libodbcpp/odbc-mock.h b/libodbcpp/odbc-mock.h new file mode 100644 index 0000000..d2bcbfe --- /dev/null +++ b/libodbcpp/odbc-mock.h @@ -0,0 +1,25 @@ +#ifndef MOCKODBCDATASOURCE_H +#define MOCKODBCDATASOURCE_H + +#include +#include +#include + +namespace ODBC { + +class DLL_PUBLIC Mock : public DB::MockServerDatabase { + public: + Mock(const std::string & master, const std::string & name, const std::vector & ss); + ~Mock(); + + protected: + void DropDatabase() const override; + + private: + DB::Connection * openConnection() const override; +}; + +} + +#endif + diff --git a/libodbcpp/odbc-modifycommand.cpp b/libodbcpp/odbc-modifycommand.cpp new file mode 100644 index 0000000..5d483c5 --- /dev/null +++ b/libodbcpp/odbc-modifycommand.cpp @@ -0,0 +1,40 @@ +#include "odbc-modifycommand.h" +#include "odbc-error.h" + +ODBC::ModifyCommand::ModifyCommand(const ODBC::Connection & c, const std::string & sql) : + DB::Command(sql), + ODBC::Command(c, sql), + DB::ModifyCommand(sql) +{ +} + +ODBC::ModifyCommand::~ModifyCommand() +{ +} + +unsigned int +ODBC::ModifyCommand::execute(bool anc) +{ + if (connection.txIsAborted()) { + throw Error("Transaction has been aborted, not issuing any more commands"); + } + RETCODE rc = SQLExecute(hStmt); + if (!SQL_SUCCEEDED(rc)) { + if (rc != SQL_NO_DATA || !anc) { + connection.abortTx(); + throw Error(rc, SQL_HANDLE_STMT, hStmt, "ODBC::ModifyCommand::execute SQLExecute"); + } + } + SQLLEN rows; + rc = SQLRowCount(hStmt, &rows); + if (!SQL_SUCCEEDED(rc)) { + connection.abortTx(); + throw Error(rc, SQL_HANDLE_STMT, hStmt, "ODBC::ModifyCommand::execute SQLRowCount"); + } + if (rows > 0 || anc) { + return rows; + } + connection.abortTx(); + throw Error("No rows affected"); +} + diff --git a/libodbcpp/odbc-modifycommand.h b/libodbcpp/odbc-modifycommand.h new file mode 100644 index 0000000..5b2a4f4 --- /dev/null +++ b/libodbcpp/odbc-modifycommand.h @@ -0,0 +1,18 @@ +#ifndef ODBC_MODIFYCOMMAND_H +#define ODBC_MODIFYCOMMAND_H + +#include +#include "odbc-command.h" + +namespace ODBC { + class ModifyCommand : public Command, public DB::ModifyCommand { + public: + ModifyCommand(const Connection &, const std::string & sql); + ~ModifyCommand(); + // Execute the command and return effected row count + unsigned int execute(bool allowNoChange = true); + }; +} + +#endif + diff --git a/libodbcpp/odbc-param.cpp b/libodbcpp/odbc-param.cpp new file mode 100644 index 0000000..cd78940 --- /dev/null +++ b/libodbcpp/odbc-param.cpp @@ -0,0 +1,124 @@ +#include +#include "odbc-param.h" +#include "odbc-command.h" +#include "odbc-error.h" +#include + +ODBC::Param::Param() : + paramCmd(NULL), + paramIdx(0), + paramBound(false) +{ +} + +ODBC::Param::Param(Command * c, unsigned int i) : + paramCmd(c), + paramIdx(i), + paramBound(false) +{ +} + +ODBC::Param::~Param(){ +} + +template +ParamType * +ODBC::Command::makeParam(unsigned int idx) +{ + if (idx >= params.size()) { + throw Error("ODBC::Command::makeParam Bind out of bounds"); + } + Param * & p = params[idx]; + if (p) { + ParamType * np = dynamic_cast(p); + if (np) { + return np; + } + delete p; + } + ParamType * np = new ParamType(this, idx); + p = np; + return np; +} + +void +ODBC::Param::bind() const +{ + if (!paramBound) { + RETCODE rc = SQLBindParameter(paramCmd->hStmt, paramIdx + 1, SQL_PARAM_INPUT, ctype(), stype(), + size(), dp(), const_cast(dataAddress()), size(), &bindLen); + if (!SQL_SUCCEEDED(rc)) { + throw Error(rc, SQL_HANDLE_STMT, paramCmd->hStmt, "ODBC::Param::bind Bind parameter"); + } + paramBound = true; + } +} + +#define SIMPLEBINDER(ctype, otype, suf) \ +void \ +ODBC::Command::bindParam##suf(unsigned int i, ctype val) \ +{ \ + ODBC::otype * p = makeParam(i); \ + *p = val; \ + p->bind(); \ +} +SIMPLEBINDER(int, SignedIntegerParam, I); +SIMPLEBINDER(long, SignedIntegerParam, I); +SIMPLEBINDER(long long, SignedIntegerParam, I); +SIMPLEBINDER(unsigned int, UnsignedIntegerParam, I); +SIMPLEBINDER(unsigned long int, UnsignedIntegerParam, I); +SIMPLEBINDER(unsigned long long int, UnsignedIntegerParam, I); + +SIMPLEBINDER(bool, BooleanParam, B); + +SIMPLEBINDER(double, FloatingPointParam, F); +SIMPLEBINDER(float, FloatingPointParam, F); + +SIMPLEBINDER(const Glib::ustring &, GlibUstringParam, S); + +SIMPLEBINDER(const boost::posix_time::ptime &, TimeStampParam, T); +SIMPLEBINDER(const boost::posix_time::time_duration &, IntervalParam, T); + +void +ODBC::Command::bindNull(unsigned int i) +{ + makeParam(i)->bind(); +} + +void +ODBC::GlibUstringParam::operator=(Glib::ustring const & d) +{ + const char * addr = data.data(); + data = d; + bindLen = d.bytes(); + paramBound &= (addr == data.data()); + if (!paramBound) { + paramBound = false; + bind(); + } +} + +void +ODBC::TimeStampParam::operator=(const boost::posix_time::ptime & d) +{ + data.year = d.date().year(); + data.month = d.date().month(); + data.day = d.date().day(); + data.hour = d.time_of_day().hours(); + data.minute = d.time_of_day().minutes(); + data.second = d.time_of_day().seconds(); + data.fraction = d.time_of_day().fractional_seconds(); +} + +void +ODBC::IntervalParam::operator=(const boost::posix_time::time_duration & d) +{ + data.interval_type = SQL_IS_DAY_TO_SECOND; + data.interval_sign = d.is_negative(); + data.intval.day_second.day = d.hours() / 24; + data.intval.day_second.hour = d.hours() % 24; + data.intval.day_second.minute = d.minutes(); + data.intval.day_second.second = d.seconds(); + data.intval.day_second.fraction = d.fractional_seconds(); +} + diff --git a/libodbcpp/odbc-param.h b/libodbcpp/odbc-param.h new file mode 100644 index 0000000..ca49c46 --- /dev/null +++ b/libodbcpp/odbc-param.h @@ -0,0 +1,135 @@ +#ifndef ODBC_PARAM_H +#define ODBC_PARAM_H + +#include +#include +#include +#include "odbc-bind.h" +#include + +namespace ODBC { + class Command; + class Param : public virtual Bind { + public: + Param(); + Param(Command *, unsigned int idx); + virtual ~Param() = 0; + void bind() const; + + virtual SQLSMALLINT stype() const = 0; // The SQL type ID + virtual SQLINTEGER dp() const = 0; // The decimal place count + virtual const void * dataAddress() const = 0; // The address of the data + + protected: + friend class Column; + mutable Command * paramCmd; + mutable unsigned int paramIdx; + mutable bool paramBound; // Has SqlBind(...) been called since last change of address? + SQLLEN dataLength; + }; + + class BooleanParam : public Param { + public: + BooleanParam() : Param() { } + BooleanParam(Command * c, unsigned int i) : Param(c, i) { bindLen = size(); } + virtual SQLSMALLINT ctype() const { return SQL_C_BIT; } + virtual SQLSMALLINT stype() const { return SQL_C_BIT; } + virtual SQLULEN size() const { return sizeof(SQLINTEGER); } + virtual SQLINTEGER dp() const { return 0; } + virtual const void * dataAddress() const { return &data; } + void operator=(const SQLINTEGER & d) { data = d; } + protected: + SQLINTEGER data; + }; + class SignedIntegerParam : public Param { + public: + SignedIntegerParam() : Param() { } + SignedIntegerParam(Command * c, unsigned int i) : Param(c, i) { bindLen = size(); } + virtual SQLSMALLINT ctype() const { return SQL_C_LONG; } + virtual SQLSMALLINT stype() const { return SQL_C_LONG; } + virtual SQLULEN size() const { return sizeof(SQLINTEGER); } + virtual SQLINTEGER dp() const { return 0; } + virtual const void * dataAddress() const { return &data; } + void operator=(const SQLINTEGER & d) { data = d; } + protected: + SQLINTEGER data; + }; + class UnsignedIntegerParam : public Param { + public: + UnsignedIntegerParam() : Param() { } + UnsignedIntegerParam(Command * c, unsigned int i) : Param(c, i) { bindLen = size(); } + virtual SQLSMALLINT ctype() const { return SQL_C_ULONG; } + virtual SQLSMALLINT stype() const { return SQL_C_ULONG; } + virtual SQLULEN size() const { return sizeof(SQLUINTEGER); } + virtual SQLINTEGER dp() const { return 0; } + virtual const void * dataAddress() const { return &data; } + void operator=(const SQLUINTEGER & d) { data = d; } + protected: + SQLUINTEGER data; + }; + class FloatingPointParam : public Param { + public: + FloatingPointParam() : Param() { } + FloatingPointParam(Command * c, unsigned int i) : Param(c, i) { bindLen = size(); } + virtual SQLSMALLINT ctype() const { return SQL_C_DOUBLE; } + virtual SQLSMALLINT stype() const { return SQL_C_DOUBLE; } + virtual SQLULEN size() const { return sizeof(SQLDOUBLE); } + virtual SQLINTEGER dp() const { return 10; } + virtual const void * dataAddress() const { return &data; } + void operator=(const SQLDOUBLE & d) { data = d; } + protected: + SQLDOUBLE data; + }; + class GlibUstringParam : public Param { + public: + GlibUstringParam() : Param() { } + GlibUstringParam(Command * c, unsigned int i) : Param(c, i) { bindLen = size(); } + virtual SQLSMALLINT ctype() const { return SQL_C_CHAR; } + virtual SQLSMALLINT stype() const { return SQL_CHAR; } + virtual SQLULEN size() const { return data.bytes(); } + virtual SQLINTEGER dp() const { return 0; } + virtual const void * dataAddress() const { return data.data(); } + void operator=(const Glib::ustring & d); + protected: + Glib::ustring data; + }; + class IntervalParam : public Param { + public: + IntervalParam() : Param() { } + IntervalParam(Command * c, unsigned int i) : Param(c, i) { bindLen = size(); } + virtual SQLSMALLINT ctype() const { return SQL_C_INTERVAL_DAY_TO_SECOND; } + virtual SQLSMALLINT stype() const { return SQL_INTERVAL_DAY_TO_SECOND; } + virtual SQLULEN size() const { return sizeof(SQL_INTERVAL_STRUCT); } + virtual SQLINTEGER dp() const { return boost::posix_time::time_res_traits::num_fractional_digits(); } + virtual const void * dataAddress() const { return &data; } + void operator=(const boost::posix_time::time_duration & d); + protected: + SQL_INTERVAL_STRUCT data; + }; + class TimeStampParam : public Param { + public: + TimeStampParam() : Param() { } + TimeStampParam(Command * c, unsigned int i) : Param(c, i) { bindLen = size(); } + virtual SQLSMALLINT ctype() const { return SQL_C_TYPE_TIMESTAMP; } + virtual SQLSMALLINT stype() const { return SQL_TYPE_TIMESTAMP; } + virtual SQLULEN size() const { return sizeof(SQL_TIMESTAMP_STRUCT); } + virtual SQLINTEGER dp() const { return boost::posix_time::time_res_traits::num_fractional_digits(); } + virtual const void * dataAddress() const { return &data; } + void operator=(const boost::posix_time::ptime & d); + protected: + SQL_TIMESTAMP_STRUCT data; + }; + class NullParam : public Param { + public: + NullParam() : Param() { } + NullParam(Command * c, unsigned int i) : Param(c, i) { bindLen = SQL_NULL_DATA; } + virtual SQLSMALLINT ctype() const { return SQL_C_LONG; } + virtual SQLSMALLINT stype() const { return SQL_C_LONG; } + virtual SQLULEN size() const { return 0; } + virtual SQLINTEGER dp() const { return 0; } + virtual const void * dataAddress() const { return NULL; } + }; +} + +#endif + diff --git a/libodbcpp/odbc-selectcommand.cpp b/libodbcpp/odbc-selectcommand.cpp new file mode 100644 index 0000000..52a45ad --- /dev/null +++ b/libodbcpp/odbc-selectcommand.cpp @@ -0,0 +1,144 @@ +#include "odbc-selectcommand.h" +#include "odbc-error.h" +#include "odbc-column.h" +#include +#include +#include +#include +#include + +ODBC::SelectCommand::SelectCommand(const Connection & c, const std::string & s) : + DB::Command(s), + ODBC::Command(c, s), + DB::SelectCommand(s) +{ +} + +ODBC::SelectCommand::~SelectCommand() +{ + if (!columns->empty()) { + RETCODE rc = SQLCloseCursor(hStmt); + if (!SQL_SUCCEEDED(rc)) { + throw Error(rc, SQL_HANDLE_STMT, hStmt, "ODBC::SelectCommand::~SelectCommand SQLCloseCursor"); + } + } +} + +bool +ODBC::SelectCommand::fetch() +{ + return fetch(SQL_FETCH_NEXT, 0); +} + +bool +ODBC::SelectCommand::fetch(SQLSMALLINT orientation, SQLLEN offset) +{ + if (columns->empty()) { + execute(); + } + RETCODE rc = SQLFetchScroll(hStmt, orientation, offset); + switch (rc) { + case SQL_SUCCESS_WITH_INFO: + default: + { + SQLCHAR sqlstatus[6]; + RETCODE diagrc = SQLGetDiagRec(SQL_HANDLE_STMT, hStmt, 1, sqlstatus, NULL, NULL, 0, NULL); + if (SQL_SUCCEEDED(diagrc)) { + if (!strncmp((const char*)sqlstatus, "01004", 5)) { + for (Columns::iterator i = columns->begin(); i != columns->end(); ++i) { + boost::dynamic_pointer_cast(*i)->resize(); + } + return fetch(SQL_FETCH_RELATIVE, 0); + } + } + if (rc != SQL_SUCCESS_WITH_INFO) { + throw Error(rc, SQL_HANDLE_STMT, hStmt, "ODBC::SelectCommand::fetch SQLFetch"); + } + } + case SQL_SUCCESS: + { + bool resized = false; + for (Columns::iterator i = columns->begin(); i != columns->end(); ++i) { + resized |= boost::dynamic_pointer_cast(*i)->resize(); + } + if (resized) { + return fetch(SQL_FETCH_RELATIVE, 0); + } + return true; + } + case SQL_NO_DATA: + return false; + } +} + +void +ODBC::SelectCommand::execute() +{ + RETCODE rc = SQLExecute(hStmt); + if (!SQL_SUCCEEDED(rc)) { + throw Error(rc, SQL_HANDLE_STMT, hStmt, "ODBC::SelectCommand::execute SQLExecute"); + } + SQLSMALLINT colCount; + if (!SQL_SUCCEEDED(rc = SQLNumResultCols(hStmt, &colCount))) { + throw Error(rc, SQL_HANDLE_STMT, hStmt, "ODBC::SelectCommand::execute SQLNumResultCols"); + } + if (colCount < 1) { + throw Error("ODBC::SelectCommand::execute No result columns"); + } + for (int col = 0; col < colCount; col++) { + SQLCHAR _colName[300]; + SQLSMALLINT nameLen, dp, nullable, bindType; + SQLULEN bindSize; + int sqlcol = col + 1; + if (!SQL_SUCCEEDED(rc = SQLDescribeCol(hStmt, sqlcol, _colName, sizeof(_colName), &nameLen, &bindType, + &bindSize, &dp, &nullable))) { + throw Error(rc, SQL_HANDLE_STMT, hStmt, "ODBC::SelectCommand::execute SQLDescribeCol for %d"); + } + Glib::ustring colName((const char *)_colName, nameLen); + DB::ColumnPtr ncol; + switch (bindType) { + case SQL_DECIMAL: + case SQL_NUMERIC: + case SQL_REAL: + case SQL_FLOAT: + case SQL_DOUBLE: + ncol = insertColumn(DB::ColumnPtr(new FloatingPointColumn(this, colName, col))); + break; + case SQL_SMALLINT: + case SQL_INTEGER: + case SQL_TINYINT: + case SQL_BIGINT: + ncol = insertColumn(DB::ColumnPtr(new SignedIntegerColumn(this, colName, col))); + break; + case SQL_TYPE_TIME: + case SQL_INTERVAL_YEAR: + case SQL_INTERVAL_MONTH: + case SQL_INTERVAL_DAY: + case SQL_INTERVAL_HOUR: + case SQL_INTERVAL_MINUTE: + case SQL_INTERVAL_SECOND: + case SQL_INTERVAL_YEAR_TO_MONTH: + case SQL_INTERVAL_DAY_TO_HOUR: + case SQL_INTERVAL_DAY_TO_MINUTE: + case SQL_INTERVAL_DAY_TO_SECOND: + case SQL_INTERVAL_HOUR_TO_MINUTE: + case SQL_INTERVAL_HOUR_TO_SECOND: + case SQL_INTERVAL_MINUTE_TO_SECOND: + ncol = insertColumn(DB::ColumnPtr(new IntervalColumn(this, colName, col))); + break; + case SQL_TIMESTAMP: + case SQL_DATETIME: + case SQL_TYPE_DATE: + case SQL_TYPE_TIMESTAMP: + ncol = insertColumn(DB::ColumnPtr(new TimeStampColumn(this, colName, col))); + break; + case SQL_UNKNOWN_TYPE: + throw Error("Unknown column type"); + default: + ncol = insertColumn(DB::ColumnPtr(new CharArrayColumn(this, colName, col, bindSize))); + break; + }; + boost::dynamic_pointer_cast(ncol)->bind(); + } +} + diff --git a/libodbcpp/odbc-selectcommand.h b/libodbcpp/odbc-selectcommand.h new file mode 100644 index 0000000..1fb2220 --- /dev/null +++ b/libodbcpp/odbc-selectcommand.h @@ -0,0 +1,22 @@ +#ifndef ODBC_SELECTCOMMAND_H +#define ODBC_SELECTCOMMAND_H + +#include +#include "odbc-command.h" + +namespace ODBC { + class Column; + class SelectCommand : public Command, public DB::SelectCommand { + public: + SelectCommand (const Connection &, const std::string & sql); + ~SelectCommand(); + bool fetch(); + void execute(); + + private: + bool fetch(SQLSMALLINT orientation = SQL_FETCH_NEXT, SQLLEN offset = 0); + }; +} + +#endif + diff --git a/libodbcpp/param.cpp b/libodbcpp/param.cpp deleted file mode 100644 index b91c07e..0000000 --- a/libodbcpp/param.cpp +++ /dev/null @@ -1,124 +0,0 @@ -#include -#include "param.h" -#include "command.h" -#include "error.h" -#include - -ODBC::Param::Param() : - paramCmd(NULL), - paramIdx(0), - paramBound(false) -{ -} - -ODBC::Param::Param(Command * c, unsigned int i) : - paramCmd(c), - paramIdx(i), - paramBound(false) -{ -} - -ODBC::Param::~Param(){ -} - -template -ParamType * -ODBC::Command::makeParam(unsigned int idx) -{ - if (idx >= params.size()) { - throw Error("ODBC::Command::makeParam Bind out of bounds"); - } - Param * & p = params[idx]; - if (p) { - ParamType * np = dynamic_cast(p); - if (np) { - return np; - } - delete p; - } - ParamType * np = new ParamType(this, idx); - p = np; - return np; -} - -void -ODBC::Param::bind() const -{ - if (!paramBound) { - RETCODE rc = SQLBindParameter(paramCmd->hStmt, paramIdx + 1, SQL_PARAM_INPUT, ctype(), stype(), - size(), dp(), const_cast(dataAddress()), size(), &bindLen); - if (!SQL_SUCCEEDED(rc)) { - throw Error(rc, SQL_HANDLE_STMT, paramCmd->hStmt, "ODBC::Param::bind Bind parameter"); - } - paramBound = true; - } -} - -#define SIMPLEBINDER(ctype, otype, suf) \ -void \ -ODBC::Command::bindParam##suf(unsigned int i, ctype val) \ -{ \ - ODBC::otype * p = makeParam(i); \ - *p = val; \ - p->bind(); \ -} -SIMPLEBINDER(int, SignedIntegerParam, I); -SIMPLEBINDER(long, SignedIntegerParam, I); -SIMPLEBINDER(long long, SignedIntegerParam, I); -SIMPLEBINDER(unsigned int, UnsignedIntegerParam, I); -SIMPLEBINDER(unsigned long int, UnsignedIntegerParam, I); -SIMPLEBINDER(unsigned long long int, UnsignedIntegerParam, I); - -SIMPLEBINDER(bool, BooleanParam, B); - -SIMPLEBINDER(double, FloatingPointParam, F); -SIMPLEBINDER(float, FloatingPointParam, F); - -SIMPLEBINDER(const Glib::ustring &, GlibUstringParam, S); - -SIMPLEBINDER(const boost::posix_time::ptime &, TimeStampParam, T); -SIMPLEBINDER(const boost::posix_time::time_duration &, IntervalParam, T); - -void -ODBC::Command::bindNull(unsigned int i) -{ - makeParam(i)->bind(); -} - -void -ODBC::GlibUstringParam::operator=(Glib::ustring const & d) -{ - const char * addr = data.data(); - data = d; - bindLen = d.bytes(); - paramBound &= (addr == data.data()); - if (!paramBound) { - paramBound = false; - bind(); - } -} - -void -ODBC::TimeStampParam::operator=(const boost::posix_time::ptime & d) -{ - data.year = d.date().year(); - data.month = d.date().month(); - data.day = d.date().day(); - data.hour = d.time_of_day().hours(); - data.minute = d.time_of_day().minutes(); - data.second = d.time_of_day().seconds(); - data.fraction = d.time_of_day().fractional_seconds(); -} - -void -ODBC::IntervalParam::operator=(const boost::posix_time::time_duration & d) -{ - data.interval_type = SQL_IS_DAY_TO_SECOND; - data.interval_sign = d.is_negative(); - data.intval.day_second.day = d.hours() / 24; - data.intval.day_second.hour = d.hours() % 24; - data.intval.day_second.minute = d.minutes(); - data.intval.day_second.second = d.seconds(); - data.intval.day_second.fraction = d.fractional_seconds(); -} - diff --git a/libodbcpp/param.h b/libodbcpp/param.h deleted file mode 100644 index d695391..0000000 --- a/libodbcpp/param.h +++ /dev/null @@ -1,135 +0,0 @@ -#ifndef ODBC_PARAM_H -#define ODBC_PARAM_H - -#include -#include -#include -#include "bind.h" -#include - -namespace ODBC { - class Command; - class Param : public virtual Bind { - public: - Param(); - Param(Command *, unsigned int idx); - virtual ~Param() = 0; - void bind() const; - - virtual SQLSMALLINT stype() const = 0; // The SQL type ID - virtual SQLINTEGER dp() const = 0; // The decimal place count - virtual const void * dataAddress() const = 0; // The address of the data - - protected: - friend class Column; - mutable Command * paramCmd; - mutable unsigned int paramIdx; - mutable bool paramBound; // Has SqlBind(...) been called since last change of address? - SQLLEN dataLength; - }; - - class BooleanParam : public Param { - public: - BooleanParam() : Param() { } - BooleanParam(Command * c, unsigned int i) : Param(c, i) { bindLen = size(); } - virtual SQLSMALLINT ctype() const { return SQL_C_BIT; } - virtual SQLSMALLINT stype() const { return SQL_C_BIT; } - virtual SQLULEN size() const { return sizeof(SQLINTEGER); } - virtual SQLINTEGER dp() const { return 0; } - virtual const void * dataAddress() const { return &data; } - void operator=(const SQLINTEGER & d) { data = d; } - protected: - SQLINTEGER data; - }; - class SignedIntegerParam : public Param { - public: - SignedIntegerParam() : Param() { } - SignedIntegerParam(Command * c, unsigned int i) : Param(c, i) { bindLen = size(); } - virtual SQLSMALLINT ctype() const { return SQL_C_LONG; } - virtual SQLSMALLINT stype() const { return SQL_C_LONG; } - virtual SQLULEN size() const { return sizeof(SQLINTEGER); } - virtual SQLINTEGER dp() const { return 0; } - virtual const void * dataAddress() const { return &data; } - void operator=(const SQLINTEGER & d) { data = d; } - protected: - SQLINTEGER data; - }; - class UnsignedIntegerParam : public Param { - public: - UnsignedIntegerParam() : Param() { } - UnsignedIntegerParam(Command * c, unsigned int i) : Param(c, i) { bindLen = size(); } - virtual SQLSMALLINT ctype() const { return SQL_C_ULONG; } - virtual SQLSMALLINT stype() const { return SQL_C_ULONG; } - virtual SQLULEN size() const { return sizeof(SQLUINTEGER); } - virtual SQLINTEGER dp() const { return 0; } - virtual const void * dataAddress() const { return &data; } - void operator=(const SQLUINTEGER & d) { data = d; } - protected: - SQLUINTEGER data; - }; - class FloatingPointParam : public Param { - public: - FloatingPointParam() : Param() { } - FloatingPointParam(Command * c, unsigned int i) : Param(c, i) { bindLen = size(); } - virtual SQLSMALLINT ctype() const { return SQL_C_DOUBLE; } - virtual SQLSMALLINT stype() const { return SQL_C_DOUBLE; } - virtual SQLULEN size() const { return sizeof(SQLDOUBLE); } - virtual SQLINTEGER dp() const { return 10; } - virtual const void * dataAddress() const { return &data; } - void operator=(const SQLDOUBLE & d) { data = d; } - protected: - SQLDOUBLE data; - }; - class GlibUstringParam : public Param { - public: - GlibUstringParam() : Param() { } - GlibUstringParam(Command * c, unsigned int i) : Param(c, i) { bindLen = size(); } - virtual SQLSMALLINT ctype() const { return SQL_C_CHAR; } - virtual SQLSMALLINT stype() const { return SQL_CHAR; } - virtual SQLULEN size() const { return data.bytes(); } - virtual SQLINTEGER dp() const { return 0; } - virtual const void * dataAddress() const { return data.data(); } - void operator=(const Glib::ustring & d); - protected: - Glib::ustring data; - }; - class IntervalParam : public Param { - public: - IntervalParam() : Param() { } - IntervalParam(Command * c, unsigned int i) : Param(c, i) { bindLen = size(); } - virtual SQLSMALLINT ctype() const { return SQL_C_INTERVAL_DAY_TO_SECOND; } - virtual SQLSMALLINT stype() const { return SQL_INTERVAL_DAY_TO_SECOND; } - virtual SQLULEN size() const { return sizeof(SQL_INTERVAL_STRUCT); } - virtual SQLINTEGER dp() const { return boost::posix_time::time_res_traits::num_fractional_digits(); } - virtual const void * dataAddress() const { return &data; } - void operator=(const boost::posix_time::time_duration & d); - protected: - SQL_INTERVAL_STRUCT data; - }; - class TimeStampParam : public Param { - public: - TimeStampParam() : Param() { } - TimeStampParam(Command * c, unsigned int i) : Param(c, i) { bindLen = size(); } - virtual SQLSMALLINT ctype() const { return SQL_C_TYPE_TIMESTAMP; } - virtual SQLSMALLINT stype() const { return SQL_TYPE_TIMESTAMP; } - virtual SQLULEN size() const { return sizeof(SQL_TIMESTAMP_STRUCT); } - virtual SQLINTEGER dp() const { return boost::posix_time::time_res_traits::num_fractional_digits(); } - virtual const void * dataAddress() const { return &data; } - void operator=(const boost::posix_time::ptime & d); - protected: - SQL_TIMESTAMP_STRUCT data; - }; - class NullParam : public Param { - public: - NullParam() : Param() { } - NullParam(Command * c, unsigned int i) : Param(c, i) { bindLen = SQL_NULL_DATA; } - virtual SQLSMALLINT ctype() const { return SQL_C_LONG; } - virtual SQLSMALLINT stype() const { return SQL_C_LONG; } - virtual SQLULEN size() const { return 0; } - virtual SQLINTEGER dp() const { return 0; } - virtual const void * dataAddress() const { return NULL; } - }; -} - -#endif - diff --git a/libodbcpp/selectcommand.cpp b/libodbcpp/selectcommand.cpp deleted file mode 100644 index 744c2c2..0000000 --- a/libodbcpp/selectcommand.cpp +++ /dev/null @@ -1,144 +0,0 @@ -#include "selectcommand.h" -#include "error.h" -#include "column.h" -#include -#include -#include -#include -#include - -ODBC::SelectCommand::SelectCommand(const Connection & c, const std::string & s) : - DB::Command(s), - ODBC::Command(c, s), - DB::SelectCommand(s) -{ -} - -ODBC::SelectCommand::~SelectCommand() -{ - if (!columns->empty()) { - RETCODE rc = SQLCloseCursor(hStmt); - if (!SQL_SUCCEEDED(rc)) { - throw Error(rc, SQL_HANDLE_STMT, hStmt, "ODBC::SelectCommand::~SelectCommand SQLCloseCursor"); - } - } -} - -bool -ODBC::SelectCommand::fetch() -{ - return fetch(SQL_FETCH_NEXT, 0); -} - -bool -ODBC::SelectCommand::fetch(SQLSMALLINT orientation, SQLLEN offset) -{ - if (columns->empty()) { - execute(); - } - RETCODE rc = SQLFetchScroll(hStmt, orientation, offset); - switch (rc) { - case SQL_SUCCESS_WITH_INFO: - default: - { - SQLCHAR sqlstatus[6]; - RETCODE diagrc = SQLGetDiagRec(SQL_HANDLE_STMT, hStmt, 1, sqlstatus, NULL, NULL, 0, NULL); - if (SQL_SUCCEEDED(diagrc)) { - if (!strncmp((const char*)sqlstatus, "01004", 5)) { - for (Columns::iterator i = columns->begin(); i != columns->end(); ++i) { - boost::dynamic_pointer_cast(*i)->resize(); - } - return fetch(SQL_FETCH_RELATIVE, 0); - } - } - if (rc != SQL_SUCCESS_WITH_INFO) { - throw Error(rc, SQL_HANDLE_STMT, hStmt, "ODBC::SelectCommand::fetch SQLFetch"); - } - } - case SQL_SUCCESS: - { - bool resized = false; - for (Columns::iterator i = columns->begin(); i != columns->end(); ++i) { - resized |= boost::dynamic_pointer_cast(*i)->resize(); - } - if (resized) { - return fetch(SQL_FETCH_RELATIVE, 0); - } - return true; - } - case SQL_NO_DATA: - return false; - } -} - -void -ODBC::SelectCommand::execute() -{ - RETCODE rc = SQLExecute(hStmt); - if (!SQL_SUCCEEDED(rc)) { - throw Error(rc, SQL_HANDLE_STMT, hStmt, "ODBC::SelectCommand::execute SQLExecute"); - } - SQLSMALLINT colCount; - if (!SQL_SUCCEEDED(rc = SQLNumResultCols(hStmt, &colCount))) { - throw Error(rc, SQL_HANDLE_STMT, hStmt, "ODBC::SelectCommand::execute SQLNumResultCols"); - } - if (colCount < 1) { - throw Error("ODBC::SelectCommand::execute No result columns"); - } - for (int col = 0; col < colCount; col++) { - SQLCHAR _colName[300]; - SQLSMALLINT nameLen, dp, nullable, bindType; - SQLULEN bindSize; - int sqlcol = col + 1; - if (!SQL_SUCCEEDED(rc = SQLDescribeCol(hStmt, sqlcol, _colName, sizeof(_colName), &nameLen, &bindType, - &bindSize, &dp, &nullable))) { - throw Error(rc, SQL_HANDLE_STMT, hStmt, "ODBC::SelectCommand::execute SQLDescribeCol for %d"); - } - Glib::ustring colName((const char *)_colName, nameLen); - DB::ColumnPtr ncol; - switch (bindType) { - case SQL_DECIMAL: - case SQL_NUMERIC: - case SQL_REAL: - case SQL_FLOAT: - case SQL_DOUBLE: - ncol = insertColumn(DB::ColumnPtr(new FloatingPointColumn(this, colName, col))); - break; - case SQL_SMALLINT: - case SQL_INTEGER: - case SQL_TINYINT: - case SQL_BIGINT: - ncol = insertColumn(DB::ColumnPtr(new SignedIntegerColumn(this, colName, col))); - break; - case SQL_TYPE_TIME: - case SQL_INTERVAL_YEAR: - case SQL_INTERVAL_MONTH: - case SQL_INTERVAL_DAY: - case SQL_INTERVAL_HOUR: - case SQL_INTERVAL_MINUTE: - case SQL_INTERVAL_SECOND: - case SQL_INTERVAL_YEAR_TO_MONTH: - case SQL_INTERVAL_DAY_TO_HOUR: - case SQL_INTERVAL_DAY_TO_MINUTE: - case SQL_INTERVAL_DAY_TO_SECOND: - case SQL_INTERVAL_HOUR_TO_MINUTE: - case SQL_INTERVAL_HOUR_TO_SECOND: - case SQL_INTERVAL_MINUTE_TO_SECOND: - ncol = insertColumn(DB::ColumnPtr(new IntervalColumn(this, colName, col))); - break; - case SQL_TIMESTAMP: - case SQL_DATETIME: - case SQL_TYPE_DATE: - case SQL_TYPE_TIMESTAMP: - ncol = insertColumn(DB::ColumnPtr(new TimeStampColumn(this, colName, col))); - break; - case SQL_UNKNOWN_TYPE: - throw Error("Unknown column type"); - default: - ncol = insertColumn(DB::ColumnPtr(new CharArrayColumn(this, colName, col, bindSize))); - break; - }; - boost::dynamic_pointer_cast(ncol)->bind(); - } -} - diff --git a/libodbcpp/selectcommand.h b/libodbcpp/selectcommand.h deleted file mode 100644 index 51dba87..0000000 --- a/libodbcpp/selectcommand.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef ODBC_SELECTCOMMAND_H -#define ODBC_SELECTCOMMAND_H - -#include -#include "command.h" - -namespace ODBC { - class Column; - class SelectCommand : public Command, public DB::SelectCommand { - public: - SelectCommand (const Connection &, const std::string & sql); - ~SelectCommand(); - bool fetch(); - void execute(); - - private: - bool fetch(SQLSMALLINT orientation = SQL_FETCH_NEXT, SQLLEN offset = 0); - }; -} - -#endif - diff --git a/libodbcpp/unittests/testodbc.cpp b/libodbcpp/unittests/testodbc.cpp index 301168c..aa36460 100644 --- a/libodbcpp/unittests/testodbc.cpp +++ b/libodbcpp/unittests/testodbc.cpp @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include #include #include -- cgit v1.2.3