summaryrefslogtreecommitdiff
path: root/libodbcpp
diff options
context:
space:
mode:
authorrandomdan <randomdan@localhost>2010-09-13 19:57:25 +0000
committerrandomdan <randomdan@localhost>2010-09-13 19:57:25 +0000
commit95bc5ac789c2f29220f76c94fc93d6379dcd00c6 (patch)
tree2af19c25a48dfb13b2db681544ad6fa82407c567 /libodbcpp
parentUse the right header for BUFSIZ (diff)
downloadlibdbpp-odbc-95bc5ac789c2f29220f76c94fc93d6379dcd00c6.tar.bz2
libdbpp-odbc-95bc5ac789c2f29220f76c94fc93d6379dcd00c6.tar.xz
libdbpp-odbc-95bc5ac789c2f29220f76c94fc93d6379dcd00c6.zip
Remove duplication in ODBC::Connection constructors
Remove pointless specialisation on _Column for strings Set cursor type to scrollable (required to refetch a row) Resize binds if fetched data is truncated Support scrolling fetch (default is old 'next record' behaviour)
Diffstat (limited to 'libodbcpp')
-rw-r--r--libodbcpp/bind.h8
-rw-r--r--libodbcpp/column.cpp16
-rw-r--r--libodbcpp/column.h10
-rw-r--r--libodbcpp/command.cpp4
-rw-r--r--libodbcpp/connection.cpp53
-rw-r--r--libodbcpp/connection.h2
-rw-r--r--libodbcpp/selectcommand.cpp19
-rw-r--r--libodbcpp/selectcommand.h2
8 files changed, 68 insertions, 46 deletions
diff --git a/libodbcpp/bind.h b/libodbcpp/bind.h
index 5baa53a..fd69900 100644
--- a/libodbcpp/bind.h
+++ b/libodbcpp/bind.h
@@ -11,7 +11,7 @@ namespace ODBC {
BindBase();
virtual ~BindBase() {}
protected:
- SQLINTEGER bindLen; // Used memory
+ SQLLEN bindLen; // Used memory
friend class Param;
friend class Column;
friend class Command;
@@ -23,12 +23,6 @@ namespace ODBC {
mutable t value;
};
typedef std::vector<char> SQLCHARVEC;
- template <>
- class Bind<SQLCHARVEC> {
- public:
- virtual ~Bind() {}
- mutable SQLCHARVEC value;
- };
}
#endif
diff --git a/libodbcpp/column.cpp b/libodbcpp/column.cpp
index 6e517a6..3d37e50 100644
--- a/libodbcpp/column.cpp
+++ b/libodbcpp/column.cpp
@@ -1,3 +1,4 @@
+#include <sqlext.h>
#include <stdio.h>
#include <stdlib.h>
#include "column.h"
@@ -17,6 +18,21 @@ ODBC::Column::~Column()
delete composeCache;
}
+void
+ODBC::Column::resize(SQLHANDLE hStmt)
+{
+}
+
+void
+ODBC::StringColumn::resize(SQLHANDLE hStmt)
+{
+ if (bindSize < bindLen) {
+ value.resize(bindLen + 1);
+ bindSize = bindLen;
+ bind(hStmt, colNo + 1, SQL_C_CHAR, &value[0], bindSize + 1);
+ }
+}
+
bool
ODBC::Column::isNull() const
{
diff --git a/libodbcpp/column.h b/libodbcpp/column.h
index 67dd0c4..c9e65ca 100644
--- a/libodbcpp/column.h
+++ b/libodbcpp/column.h
@@ -10,6 +10,7 @@ namespace ODBC {
Column(const Glib::ustring &, unsigned int);
virtual ~Column();
void bind(SQLHANDLE, SQLUINTEGER, SQLSMALLINT, void*, size_t);
+ virtual void resize(SQLHANDLE);
operator int () const;
operator unsigned int () const;
operator long long () const;
@@ -32,8 +33,7 @@ namespace ODBC {
const Glib::ustring name;
protected:
mutable Glib::ustring * composeCache;
- private:
- SQLUINTEGER bindSize; // Allocated memory
+ SQLLEN bindSize; // Allocated memory
friend class SelectCommand;
};
template <class t>
@@ -47,6 +47,12 @@ namespace ODBC {
int writeToBuf(char ** buf) const;
int writeToBuf(char ** buf, const char * fmt) const;
};
+ class StringColumn : public _Column<SQLCHARVEC> {
+ public:
+ StringColumn(const Glib::ustring & n, unsigned int i) :
+ _Column<SQLCHARVEC>(n, i) { }
+ void resize(SQLHANDLE);
+ };
}
void operator << (SQL_TIMESTAMP_STRUCT & target, const struct tm &);
diff --git a/libodbcpp/command.cpp b/libodbcpp/command.cpp
index 4ceb825..50dd679 100644
--- a/libodbcpp/command.cpp
+++ b/libodbcpp/command.cpp
@@ -11,6 +11,10 @@ ODBC::Command::Command(const Connection & c, const std::string & s) :
if (rc != SQL_SUCCESS) {
throw Error(rc, SQL_HANDLE_STMT, hStmt, "Allocate statement handle");
}
+ rc = SQLSetStmtAttr(hStmt, SQL_ATTR_CURSOR_TYPE, (SQLPOINTER)SQL_CURSOR_DYNAMIC, 0);
+ if ((rc != SQL_SUCCESS)) {
+ throw ConnectionError(rc, SQL_HANDLE_STMT, hStmt, "Set scrollable cursor");
+ }
rc = SQLPrepare(hStmt, (SQLCHAR*)sql.c_str(), sql.length());
if (rc != SQL_SUCCESS) {
SQLFreeHandle(SQL_HANDLE_STMT, hStmt);
diff --git a/libodbcpp/connection.cpp b/libodbcpp/connection.cpp
index ef8fdbb..79c0f9d 100644
--- a/libodbcpp/connection.cpp
+++ b/libodbcpp/connection.cpp
@@ -11,6 +11,18 @@ ODBC::Connection::Connection(const DSN& d) :
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 ((dberr != SQL_SUCCESS)) {
+ throw ConnectionError(dberr, SQL_HANDLE_DBC, conn, "Connect");
+ }
+ connectPost();
+}
+
+void
+ODBC::Connection::connectPre()
+{
SQLRETURN dberr = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env);
if ((dberr != SQL_SUCCESS)) {
throw ConnectionError(dberr, SQL_HANDLE_ENV, env, "Allocate handle");
@@ -30,14 +42,12 @@ ODBC::Connection::Connection(const DSN& d) :
if ((dberr != SQL_SUCCESS)) {
throw ConnectionError(dberr, SQL_HANDLE_ENV, env, "Set connection attributes");
}
+}
- 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 ((dberr != SQL_SUCCESS)) {
- throw ConnectionError(dberr, SQL_HANDLE_DBC, conn, "Connect");
- }
-
- dberr = SQLSetConnectOption(conn, SQL_ATTR_AUTOCOMMIT, SQL_AUTOCOMMIT_ON);
+void
+ODBC::Connection::connectPost()
+{
+ RETCODE dberr = SQLSetConnectOption(conn, SQL_ATTR_AUTOCOMMIT, SQL_AUTOCOMMIT_ON);
if ((dberr != SQL_SUCCESS)) {
throw ConnectionError(dberr, SQL_HANDLE_DBC, conn, "Set default auto commit");
}
@@ -49,35 +59,12 @@ ODBC::Connection::Connection(const std::string & s) :
txDepth(0),
txAborted(false)
{
- SQLRETURN dberr = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env);
- if ((dberr != SQL_SUCCESS)) {
- throw ConnectionError(dberr, SQL_HANDLE_ENV, env, "Allocate handle");
- }
-
- dberr = SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0);
- if ((dberr != SQL_SUCCESS)) {
- throw ConnectionError(dberr, SQL_HANDLE_ENV, env, "Set ODBC version");
- }
-
- dberr = SQLAllocHandle(SQL_HANDLE_DBC, env, &conn);
- if ((dberr != SQL_SUCCESS)) {
- throw ConnectionError(dberr, SQL_HANDLE_ENV, env, "Allocate DBC handle");
- }
-
- dberr = SQLSetConnectAttr(conn, SQL_LOGIN_TIMEOUT, (SQLPOINTER *)5, 0);
- if ((dberr != SQL_SUCCESS)) {
- throw ConnectionError(dberr, SQL_HANDLE_ENV, env, "Set connection attributes");
- }
-
- dberr = SQLDriverConnect(conn, NULL, (SQLCHAR*)s.c_str(), s.length(), NULL, 0, NULL, SQL_DRIVER_NOPROMPT);
+ connectPre();
+ RETCODE dberr = SQLDriverConnect(conn, NULL, (SQLCHAR*)s.c_str(), s.length(), NULL, 0, NULL, SQL_DRIVER_NOPROMPT);
if ((dberr != SQL_SUCCESS)) {
throw ConnectionError(dberr, SQL_HANDLE_DBC, conn, "Connect");
}
-
- dberr = SQLSetConnectOption(conn, SQL_ATTR_AUTOCOMMIT, SQL_AUTOCOMMIT_ON);
- if ((dberr != SQL_SUCCESS)) {
- throw ConnectionError(dberr, SQL_HANDLE_DBC, conn, "Set default auto commit");
- }
+ connectPost();
}
ODBC::Connection::~Connection()
diff --git a/libodbcpp/connection.h b/libodbcpp/connection.h
index 0d2e9d4..86ff7d8 100644
--- a/libodbcpp/connection.h
+++ b/libodbcpp/connection.h
@@ -24,6 +24,8 @@ namespace ODBC {
SQLINTEGER getAttrInt(SQLINTEGER) const;
private:
+ void connectPre();
+ void connectPost();
mutable unsigned int txDepth;
mutable bool txAborted;
};
diff --git a/libodbcpp/selectcommand.cpp b/libodbcpp/selectcommand.cpp
index 88a071f..3b903d6 100644
--- a/libodbcpp/selectcommand.cpp
+++ b/libodbcpp/selectcommand.cpp
@@ -3,6 +3,7 @@
#include "column.h"
#include <sqlext.h>
#include <stdio.h>
+#include <string.h>
ODBC::SelectCommand::SelectCommand(const Connection & c, const std::string & s) :
Command(c, s)
@@ -26,12 +27,12 @@ ODBC::SelectCommand::~SelectCommand()
}
bool
-ODBC::SelectCommand::fetch()
+ODBC::SelectCommand::fetch(SQLSMALLINT orientation, SQLLEN offset)
{
if (columns.size() == 0) {
execute();
}
- RETCODE rc = SQLFetch(hStmt);
+ RETCODE rc = SQLFetchScroll(hStmt, orientation, offset);
switch (rc) {
case SQL_SUCCESS:
for (Columns::iterator i = columns.begin(); i != columns.end(); i++) {
@@ -42,6 +43,18 @@ ODBC::SelectCommand::fetch()
case SQL_NO_DATA:
return false;
default:
+ {
+ SQLCHAR sqlstatus[5];
+ 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++) {
+ (*i)->resize(hStmt);
+ }
+ return fetch(SQL_FETCH_RELATIVE, 0);
+ }
+ }
+ }
throw Error(rc, SQL_HANDLE_STMT, hStmt, "%s: SQLFetch",
__FUNCTION__);
}
@@ -87,7 +100,7 @@ ODBC::SelectCommand::execute()
case SQL_VARCHAR:
case SQL_LONGVARCHAR:
{
- _Column<SQLCHARVEC>* s = new _Column<SQLCHARVEC>(colName, col);
+ StringColumn* s = new StringColumn(colName, col);
s->value.resize(bindSize + 1);
s->bind(hStmt, sqlcol, SQL_C_CHAR, &s->value[0], bindSize + 1);
columns[col] = s;
diff --git a/libodbcpp/selectcommand.h b/libodbcpp/selectcommand.h
index 541cd08..c523f25 100644
--- a/libodbcpp/selectcommand.h
+++ b/libodbcpp/selectcommand.h
@@ -10,7 +10,7 @@ namespace ODBC {
public:
SelectCommand (const Connection &, const std::string & sql);
~SelectCommand();
- bool fetch();
+ bool fetch(SQLSMALLINT orientation = SQL_FETCH_NEXT, SQLLEN offset = 0);
const Column & operator[](unsigned int col) const;
const Column & operator[](const Glib::ustring &) const;
unsigned int columnCount() const;