SOCI Logo Get SOCI at SourceForge.net. Fast, secure and Free Open Source software downloads

statement.cpp

Go to the documentation of this file.
00001 //
00002 // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton, David Courtney
00003 // Distributed under the Boost Software License, Version 1.0.
00004 // (See accompanying file LICENSE_1_0.txt or copy at
00005 // http://www.boost.org/LICENSE_1_0.txt)
00006 //
00007 
00008 #define SOCI_ODBC_SOURCE
00009 #include "soci-odbc.h"
00010 #include <cctype>
00011 #include <sstream>
00012 #include <cstring>
00013 
00014 #ifdef _MSC_VER
00015 // disables the warning about converting int to void*.  This is a 64 bit compatibility
00016 // warning, but odbc requires the value to be converted on this line
00017 // SQLSetStmtAttr(hstmt_, SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER)number, 0);
00018 #pragma warning(disable:4312)
00019 #endif
00020 
00021 using namespace soci;
00022 using namespace soci::details;
00023 
00024 
00025 odbc_statement_backend::odbc_statement_backend(odbc_session_backend &session)
00026     : session_(session), hstmt_(0), numRowsFetched_(0),
00027       hasVectorUseElements_(false), boundByName_(false), boundByPos_(false)
00028 {
00029 }
00030 
00031 void odbc_statement_backend::alloc()
00032 {
00033     SQLRETURN rc;
00034 
00035     // Allocate environment handle
00036     rc = SQLAllocHandle(SQL_HANDLE_STMT, session_.hdbc_, &hstmt_);
00037     if (is_odbc_error(rc))
00038     {
00039         throw odbc_soci_error(SQL_HANDLE_DBC, session_.hdbc_,
00040             "Allocating statement");
00041     }
00042 }
00043 
00044 void odbc_statement_backend::clean_up()
00045 {
00046     SQLFreeHandle(SQL_HANDLE_STMT, hstmt_);
00047 }
00048 
00049 
00050 void odbc_statement_backend::prepare(std::string const & query,
00051     statement_type /* eType */)
00052 {
00053     // rewrite the query by transforming all named parameters into
00054     // the ODBC numbers ones (:abc -> $1, etc.)
00055 
00056     enum { eNormal, eInQuotes, eInName, eInAccessDate } state = eNormal;
00057 
00058     std::string name;
00059 
00060     for (std::string::const_iterator it = query.begin(), end = query.end();
00061          it != end; ++it)
00062     {
00063         switch (state)
00064         {
00065         case eNormal:
00066             if (*it == '\'')
00067             {
00068                 query_ += *it;
00069                 state = eInQuotes;
00070             }
00071             else if (*it == '#')
00072             {
00073                 query_ += *it;
00074                 state = eInAccessDate;
00075             }
00076             else if (*it == ':')
00077             {
00078                 state = eInName;
00079             }
00080             else // regular character, stay in the same state
00081             {
00082                 query_ += *it;
00083             }
00084             break;
00085         case eInQuotes:
00086             if (*it == '\'')
00087             {
00088                 query_ += *it;
00089                 state = eNormal;
00090             }
00091             else // regular quoted character
00092             {
00093                 query_ += *it;
00094             }
00095             break;
00096         case eInName:
00097             if (std::isalnum(*it) || *it == '_')
00098             {
00099                 name += *it;
00100             }
00101             else // end of name
00102             {
00103                 names_.push_back(name);
00104                 name.clear();
00105                 std::ostringstream ss;
00106                 ss << '?';
00107                 query_ += ss.str();
00108                 query_ += *it;
00109                 state = eNormal;
00110             }
00111             break;
00112         case eInAccessDate:
00113             if (*it == '#')
00114             {
00115                 query_ += *it;
00116                 state = eNormal;
00117             }
00118             else // regular quoted character
00119             {
00120                 query_ += *it;
00121             }
00122             break;
00123         }
00124     }
00125 
00126     if (state == eInName)
00127     {
00128         names_.push_back(name);
00129         std::ostringstream ss;
00130         ss << '?';
00131         query_ += ss.str();
00132     }
00133 
00134     SQLRETURN rc = SQLPrepare(hstmt_, (SQLCHAR*)query_.c_str(), (SQLINTEGER)query_.size());
00135     if (is_odbc_error(rc))
00136     {
00137         throw odbc_soci_error(SQL_HANDLE_STMT, hstmt_,
00138                          query_.c_str());
00139     }
00140 }
00141 
00142 statement_backend::exec_fetch_result
00143 odbc_statement_backend::execute(int number)
00144 {
00145     // made this static because MSVC debugger was reporting
00146     // that there was an attempt to use rows_processed after the stack
00147     // was destroyed.  Some ODBC clean_up ?
00148     static SQLUSMALLINT rows_processed = 0;
00149 
00150     if (hasVectorUseElements_)
00151     {
00152         SQLSetStmtAttr(hstmt_, SQL_ATTR_PARAMS_PROCESSED_PTR, &rows_processed, 0);
00153     }
00154 
00155     // if we are called twice for the same statement we need to close the open
00156     // cursor or an "invalid cursor state" error will occur on execute
00157     SQLCloseCursor(hstmt_);
00158 
00159     SQLRETURN rc = SQLExecute(hstmt_);
00160     if (is_odbc_error(rc))
00161     {
00162         throw odbc_soci_error(SQL_HANDLE_STMT, hstmt_,
00163                          "Statement Execute");
00164     }
00165 
00166     SQLSMALLINT colCount;
00167     SQLNumResultCols(hstmt_, &colCount);
00168 
00169     if (number > 0 && colCount > 0)
00170     {
00171         return fetch(number);
00172     }
00173 
00174     return ef_success;
00175 }
00176 
00177 statement_backend::exec_fetch_result
00178 odbc_statement_backend::fetch(int number)
00179 {
00180     numRowsFetched_ = 0;
00181 
00182     SQLSetStmtAttr(hstmt_, SQL_ATTR_ROW_BIND_TYPE, SQL_BIND_BY_COLUMN, 0);
00183     SQLSetStmtAttr(hstmt_, SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER)number, 0);
00184     SQLSetStmtAttr(hstmt_, SQL_ATTR_ROWS_FETCHED_PTR, &numRowsFetched_, 0);
00185 
00186     SQLRETURN rc = SQLFetch(hstmt_);
00187 
00188     if (SQL_NO_DATA == rc)
00189     {
00190         return ef_no_data;
00191     }
00192 
00193     if (is_odbc_error(rc))
00194     {
00195         throw odbc_soci_error(SQL_HANDLE_STMT, hstmt_,
00196                          "Statement Fetch");
00197     }
00198 
00199     return ef_success;
00200 }
00201 
00202 int odbc_statement_backend::get_number_of_rows()
00203 {
00204     return numRowsFetched_;
00205 }
00206 
00207 std::string odbc_statement_backend::rewrite_for_procedure_call(
00208     std::string const &query)
00209 {
00210     return query;
00211 }
00212 
00213 int odbc_statement_backend::prepare_for_describe()
00214 {
00215     SQLSMALLINT numCols;
00216     SQLNumResultCols(hstmt_, &numCols);
00217     return numCols;
00218 }
00219 
00220 void odbc_statement_backend::describe_column(int colNum, data_type & type,
00221                                           std::string & columnName)
00222 {
00223     SQLCHAR colNameBuffer[2048];
00224     SQLSMALLINT colNameBufferOverflow;
00225     SQLSMALLINT dataType;
00226     SQLULEN colSize;
00227     SQLSMALLINT decDigits;
00228     SQLSMALLINT isNullable;
00229 
00230     SQLRETURN rc = SQLDescribeCol(hstmt_, static_cast<SQLUSMALLINT>(colNum),
00231                                   colNameBuffer, 2048,
00232                                   &colNameBufferOverflow, &dataType,
00233                                   &colSize, &decDigits, &isNullable);
00234 
00235     if (is_odbc_error(rc))
00236     {
00237         throw odbc_soci_error(SQL_HANDLE_STMT, hstmt_,
00238                          "describe Column");
00239     }
00240 
00241     char const *name = reinterpret_cast<char const *>(colNameBuffer);
00242     columnName.assign(name, std::strlen(name));
00243 
00244     switch (dataType)
00245     {
00246     case SQL_TYPE_DATE:
00247     case SQL_TYPE_TIME:
00248     case SQL_TYPE_TIMESTAMP:
00249         type = dt_date;
00250         break;
00251     case SQL_DOUBLE:
00252     case SQL_DECIMAL:
00253     case SQL_REAL:
00254     case SQL_FLOAT:
00255     case SQL_NUMERIC:
00256         type = dt_double;
00257         break;
00258     case SQL_TINYINT:
00259     case SQL_SMALLINT:
00260     case SQL_INTEGER:
00261     case SQL_BIGINT:
00262         type = dt_integer;
00263         break;
00264     case SQL_CHAR:
00265     case SQL_VARCHAR:
00266     default:
00267         type = dt_string;
00268         break;
00269     }
00270 }
00271 
00272 std::size_t odbc_statement_backend::column_size(int colNum)
00273 {
00274     SQLCHAR colNameBuffer[2048];
00275     SQLSMALLINT colNameBufferOverflow;
00276     SQLSMALLINT dataType;
00277     SQLULEN colSize;
00278     SQLSMALLINT decDigits;
00279     SQLSMALLINT isNullable;
00280 
00281     SQLRETURN rc = SQLDescribeCol(hstmt_, static_cast<SQLUSMALLINT>(colNum),
00282                                   colNameBuffer, 2048,
00283                                   &colNameBufferOverflow, &dataType,
00284                                   &colSize, &decDigits, &isNullable);
00285 
00286     if (is_odbc_error(rc))
00287     {
00288         throw odbc_soci_error(SQL_HANDLE_STMT, hstmt_,
00289                          "column size");
00290     }
00291 
00292     return colSize;
00293 }
00294 
00295 odbc_standard_into_type_backend * odbc_statement_backend::make_into_type_backend()
00296 {
00297     return new odbc_standard_into_type_backend(*this);
00298 }
00299 
00300 odbc_standard_use_type_backend * odbc_statement_backend::make_use_type_backend()
00301 {
00302     return new odbc_standard_use_type_backend(*this);
00303 }
00304 
00305 odbc_vector_into_type_backend *
00306 odbc_statement_backend::make_vector_into_type_backend()
00307 {
00308     return new odbc_vector_into_type_backend(*this);
00309 }
00310 
00311 odbc_vector_use_type_backend * odbc_statement_backend::make_vector_use_type_backend()
00312 {
00313     hasVectorUseElements_ = true;
00314     return new odbc_vector_use_type_backend(*this);
00315 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
SourceForge Logo

Generated on Sun Oct 3 2010 17:42:16 for EXTRAS-SOCI by Doxygen 1.7.1