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 }
Generated on Sun Oct 3 2010 17:42:16 for EXTRAS-SOCI by Doxygen 1.7.1