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 #include "soci-sqlite3.h"
00008 // std
00009 #include <algorithm>
00010 #include <sstream>
00011 #include <string>
00012 
00013 #ifdef _MSC_VER
00014 #pragma warning(disable:4355)
00015 #endif
00016 
00017 using namespace soci;
00018 using namespace soci::details;
00019 using namespace sqlite_api;
00020 
00021 sqlite3_statement_backend::sqlite3_statement_backend(
00022     sqlite3_session_backend &session)
00023     : session_(session), stmt_(0), dataCache_(), useData_(0),
00024       databaseReady_(false), boundByName_(false), boundByPos_(false)
00025 {
00026 }
00027 
00028 void sqlite3_statement_backend::alloc()
00029 {
00030     // ...
00031 }
00032 
00033 void sqlite3_statement_backend::clean_up()
00034 {
00035     if (stmt_)
00036     {
00037         sqlite3_finalize(stmt_);
00038         stmt_ = 0;
00039         databaseReady_ = false;
00040     }
00041 }
00042 
00043 void sqlite3_statement_backend::prepare(std::string const & query,
00044     statement_type /* eType */)
00045 {
00046     clean_up();
00047 
00048     char const* tail = 0; // unused;
00049     int res = sqlite3_prepare(session_.conn_,
00050                               query.c_str(),
00051                               static_cast<int>(query.size()),
00052                               &stmt_,
00053                               &tail);
00054     if (res != SQLITE_OK)
00055     {
00056         char const* zErrMsg = sqlite3_errmsg(session_.conn_);
00057 
00058         std::ostringstream ss;
00059         ss << "sqlite3_statement_backend::prepare: "
00060            << zErrMsg;
00061         throw soci_error(ss.str());
00062     }
00063     databaseReady_ = true;
00064 }
00065 
00066 // sqlite3_reset needs to be called before a prepared statment can
00067 // be executed a second time.
00068 void sqlite3_statement_backend::resetIfNeeded()
00069 {
00070     if (stmt_ && databaseReady_ == false)
00071     {
00072         int res = sqlite3_reset(stmt_);
00073         if (SQLITE_OK == res)
00074         {
00075             databaseReady_ = true;
00076         }
00077     }
00078 }
00079 
00080 // This is used by bulk operations
00081 statement_backend::exec_fetch_result
00082 sqlite3_statement_backend::loadRS(int totalRows)
00083 {
00084     statement_backend::exec_fetch_result retVal = ef_success;
00085     int numCols = -1;
00086     int i = 0;
00087 
00088     if (!databaseReady_)
00089     {
00090         retVal = ef_no_data;
00091     }
00092     else
00093     {
00094         // make the vector big enough to hold the data we need
00095         dataCache_.resize(totalRows);
00096 
00097         for (i = 0; i < totalRows && databaseReady_; ++i)
00098         {
00099             int res = sqlite3_step(stmt_);
00100 
00101             if (SQLITE_DONE == res)
00102             {
00103                 databaseReady_ = false;
00104                 retVal = ef_no_data;
00105                 break;
00106             }
00107             else if (SQLITE_ROW == res)
00108             {
00109                 // only need to set the number of columns once
00110                 if (-1 == numCols)
00111                 {
00112                     numCols = sqlite3_column_count(stmt_);
00113                     for (sqlite3_recordset::iterator it = dataCache_.begin();
00114                         it != dataCache_.end(); ++it)
00115                     {
00116                         (*it).resize(numCols);
00117                     }
00118                 }
00119                 for (int c = 0; c < numCols; ++c)
00120                 {
00121                     char const* buf = reinterpret_cast<char const*>(
00122                                         sqlite3_column_text(stmt_, c));
00123                     bool isNull = false;
00124                     if (0 == buf)
00125                     {
00126                         isNull = true;
00127                         buf = "";
00128                     }
00129                     dataCache_[i][c].data_ = buf;
00130                     dataCache_[i][c].isNull_ = isNull;
00131                 }
00132             }
00133             else
00134             {
00135                 clean_up();
00136                 char const* zErrMsg = sqlite3_errmsg(session_.conn_);
00137                 std::ostringstream ss;
00138                 ss << "sqlite3_statement_backend::loadRS: "
00139                    << zErrMsg;
00140                 throw soci_error(ss.str());
00141             }
00142         }
00143     }
00144     // if we read less than requested then shrink the vector
00145     dataCache_.resize(i);
00146 
00147     return retVal;
00148 }
00149 
00150 // This is used for non-bulk operations
00151 statement_backend::exec_fetch_result
00152 sqlite3_statement_backend::loadOne()
00153 {
00154     statement_backend::exec_fetch_result retVal = ef_success;
00155 
00156     int res = sqlite3_step(stmt_);
00157 
00158     if (SQLITE_DONE == res)
00159     {
00160         databaseReady_ = false;
00161         retVal = ef_no_data;
00162     }
00163     else if (SQLITE_ROW == res)
00164     {
00165     }
00166     else
00167     {
00168         clean_up();
00169 
00170         char const* zErrMsg = sqlite3_errmsg(session_.conn_);
00171 
00172         std::ostringstream ss;
00173         ss << "sqlite3_statement_backend::loadOne: "
00174            << zErrMsg;
00175         throw soci_error(ss.str());
00176     }
00177 
00178     return retVal;
00179 }
00180 
00181 // Execute statements once for every row of useData
00182 statement_backend::exec_fetch_result
00183 sqlite3_statement_backend::bindAndExecute(int number)
00184 {
00185     statement_backend::exec_fetch_result retVal = ef_no_data;
00186 
00187     int rows = static_cast<int>(useData_.size());
00188 
00189     for (int row = 0; row < rows; ++row)
00190     {
00191         sqlite3_reset(stmt_);
00192 
00193         int totalPositions = static_cast<int>(useData_[0].size());
00194         for (int pos = 1; pos <= totalPositions; ++pos)
00195         {
00196             int bindRes = SQLITE_OK;
00197             const sqlite3_column& curCol = useData_[row][pos-1];
00198             if (curCol.isNull_)
00199             {
00200                 bindRes = sqlite3_bind_null(stmt_, pos);
00201             }
00202             else if (curCol.blobBuf_)
00203             {
00204                 bindRes = sqlite3_bind_blob(stmt_, pos,
00205                                             curCol.blobBuf_,
00206                                             curCol.blobSize_,
00207                                             SQLITE_STATIC);
00208             }
00209             else
00210             {
00211                 bindRes = sqlite3_bind_text(stmt_, pos,
00212                                             curCol.data_.c_str(),
00213                                             static_cast<int>(curCol.data_.length()),
00214                                             SQLITE_STATIC);
00215             }
00216 
00217             if (SQLITE_OK != bindRes)
00218             {
00219                 throw soci_error("Failure to bind on bulk operations");
00220             }
00221         }
00222 
00223         // Handle the case where there are both into and use elements
00224         // in the same query and one of the into binds to a vector object.
00225         if (1 == rows && number != rows)
00226         {
00227             return loadRS(number);
00228         }
00229 
00230         retVal = loadOne(); //execute each bound line
00231     }
00232     return retVal;
00233 }
00234 
00235 statement_backend::exec_fetch_result
00236 sqlite3_statement_backend::execute(int number)
00237 {
00238     if (stmt_ == NULL)
00239     {
00240         throw soci_error("No sqlite statement created");
00241     }
00242 
00243     sqlite3_reset(stmt_);
00244     databaseReady_ = true;
00245 
00246     statement_backend::exec_fetch_result retVal = ef_no_data;
00247 
00248     if (useData_.empty() == false)
00249     {
00250            retVal = bindAndExecute(number);
00251     }
00252     else
00253     {
00254         if (1 == number)
00255         {
00256             retVal = loadOne();
00257         }
00258         else
00259         {
00260             retVal = loadRS(number);
00261         }
00262     }
00263 
00264     return retVal;
00265 }
00266 
00267 statement_backend::exec_fetch_result
00268 sqlite3_statement_backend::fetch(int number)
00269 {
00270     return loadRS(number);
00271 }
00272 
00273 int sqlite3_statement_backend::get_number_of_rows()
00274 {
00275     return static_cast<int>(dataCache_.size());
00276 }
00277 
00278 std::string sqlite3_statement_backend::rewrite_for_procedure_call(
00279     std::string const &query)
00280 {
00281     return query;
00282 }
00283 
00284 int sqlite3_statement_backend::prepare_for_describe()
00285 {
00286     return sqlite3_column_count(stmt_);
00287 }
00288 
00289 void sqlite3_statement_backend::describe_column(int colNum, data_type & type,
00290                                              std::string & columnName)
00291 {
00292 
00293     columnName = sqlite3_column_name(stmt_, colNum-1);
00294 
00295     // This is a hack, but the sqlite3 type system does not
00296     // have a date or time field.  Also it does not reliably
00297     // id other data types.  It has a tendency to see everything
00298     // as text.  sqlite3_column_decltype returns the text that is
00299     // used in the create table statement
00300     bool typeFound = false;
00301 
00302     char const* declType = sqlite3_column_decltype(stmt_, colNum-1);
00303 
00304     if ( declType == NULL )
00305     {
00306         static char const* s_char = "char";
00307         declType = s_char;
00308     }
00309 
00310     std::string dt = declType;
00311 
00312     // do all comparisions in lower case
00313     std::transform(dt.begin(), dt.end(), dt.begin(), tolower);
00314 
00315     if (dt.find("time", 0) != std::string::npos)
00316     {
00317         type = dt_date;
00318         typeFound = true;
00319     }
00320     if (dt.find("date", 0) != std::string::npos)
00321     {
00322         type = dt_date;
00323         typeFound = true;
00324     }
00325     if (dt.find("int", 0) != std::string::npos)
00326     {
00327         type = dt_integer;
00328         typeFound = true;
00329     }
00330     if (dt.find("float", 0) != std::string::npos)
00331     {
00332         type = dt_double;
00333         typeFound = true;
00334     }
00335     if (dt.find("text", 0) != std::string::npos)
00336     {
00337         type = dt_string;
00338         typeFound = true;
00339     }
00340     if (dt.find("char", 0) != std::string::npos)
00341     {
00342         type = dt_string;
00343         typeFound = true;
00344     }
00345     if (dt.find("boolean", 0) != std::string::npos)
00346     {
00347         type = dt_integer;
00348         typeFound = true;
00349     }
00350 
00351     if (typeFound)
00352     {
00353         return;
00354     }
00355 
00356     // try to get it from the weak ass type system
00357 
00358     // total hack - execute the statment once to get the column types
00359     // then clear so it can be executed again
00360     sqlite3_step(stmt_);
00361 
00362     int sqlite3_type = sqlite3_column_type(stmt_, colNum-1);
00363     switch (sqlite3_type)
00364     {
00365     case SQLITE_INTEGER: type = dt_integer; break;
00366     case SQLITE_FLOAT: type = dt_double; break;
00367     case SQLITE_BLOB:
00368     case SQLITE_TEXT: type = dt_string; break;
00369     default: type = dt_string; break;
00370     }
00371 
00372     sqlite3_reset(stmt_);
00373 }
00374 
00375 sqlite3_standard_into_type_backend *
00376 sqlite3_statement_backend::make_into_type_backend()
00377 {
00378     return new sqlite3_standard_into_type_backend(*this);
00379 }
00380 
00381 sqlite3_standard_use_type_backend * sqlite3_statement_backend::make_use_type_backend()
00382 {
00383     return new sqlite3_standard_use_type_backend(*this);
00384 }
00385 
00386 sqlite3_vector_into_type_backend *
00387 sqlite3_statement_backend::make_vector_into_type_backend()
00388 {
00389     return new sqlite3_vector_into_type_backend(*this);
00390 }
00391 
00392 sqlite3_vector_use_type_backend *
00393 sqlite3_statement_backend::make_vector_use_type_backend()
00394 {
00395     return new sqlite3_vector_use_type_backend(*this);
00396 }
 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