summaryrefslogtreecommitdiff
path: root/libodbcpp/odbc-selectcommand.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libodbcpp/odbc-selectcommand.cpp')
-rw-r--r--libodbcpp/odbc-selectcommand.cpp144
1 files changed, 144 insertions, 0 deletions
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 <sqlext.h>
+#include <stdio.h>
+#include <string.h>
+#include <boost/multi_index_container.hpp>
+#include <boost/multi_index/ordered_index.hpp>
+
+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<Column>(*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<Column>(*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<Column>(ncol)->bind();
+ }
+}
+