File indexing completed on 2025-02-23 05:15:15
0001 // 0002 // Copyright (C) 2011-2013 Denis Chapligin 0003 // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton 0004 // Distributed under the Boost Software License, Version 1.0. 0005 // (See accompanying file LICENSE_1_0.txt or copy at 0006 // http://www.boost.org/LICENSE_1_0.txt) 0007 // 0008 0009 #define SOCI_DB2_SOURCE 0010 #include "soci/db2/soci-db2.h" 0011 #include <cctype> 0012 0013 using namespace soci; 0014 using namespace soci::details; 0015 0016 db2_statement_backend::db2_statement_backend(db2_session_backend &session) 0017 : session_(session),hasVectorUseElements(false),use_binding_method_(details::db2::BOUND_BY_NONE) 0018 { 0019 } 0020 0021 void db2_statement_backend::alloc() 0022 { 0023 SQLRETURN cliRC = SQL_SUCCESS; 0024 0025 cliRC = SQLAllocHandle(SQL_HANDLE_STMT,session_.hDbc,&hStmt); 0026 if (cliRC != SQL_SUCCESS) { 0027 throw db2_soci_error("Error while allocation statement handle",cliRC); 0028 } 0029 } 0030 0031 void db2_statement_backend::clean_up() 0032 { 0033 SQLRETURN cliRC = SQL_SUCCESS; 0034 0035 cliRC=SQLFreeHandle(SQL_HANDLE_STMT,hStmt); 0036 if (cliRC != SQL_SUCCESS) { 0037 throw db2_soci_error(db2_soci_error::sqlState("Statement handle clean-up error",SQL_HANDLE_STMT,hStmt),cliRC); 0038 } 0039 } 0040 0041 void db2_statement_backend::prepare(std::string const & query , 0042 statement_type /* eType */) 0043 { 0044 // rewrite the query by transforming all named parameters into 0045 // the markers (:abc -> ?, etc.) 0046 0047 enum { normal, in_quotes, in_name } state = normal; 0048 0049 std::string name; 0050 0051 for (std::string::const_iterator it = query.begin(), end = query.end(); 0052 it != end; ++it) 0053 { 0054 switch (state) 0055 { 0056 case normal: 0057 if (*it == '\'') 0058 { 0059 query_ += *it; 0060 state = in_quotes; 0061 } 0062 else if (*it == ':') 0063 { 0064 // Check whether this is a cast operator (e.g. 23::float) 0065 // and treat it as a special case, not as a named binding 0066 const std::string::const_iterator next_it = it + 1; 0067 if ((next_it != end) && (*next_it == ':')) 0068 { 0069 query_ += "::"; 0070 ++it; 0071 } 0072 else 0073 { 0074 state = in_name; 0075 } 0076 } 0077 else // regular character, stay in the same state 0078 { 0079 query_ += *it; 0080 } 0081 break; 0082 case in_quotes: 0083 if (*it == '\'') 0084 { 0085 query_ += *it; 0086 state = normal; 0087 } 0088 else // regular quoted character 0089 { 0090 query_ += *it; 0091 } 0092 break; 0093 case in_name: 0094 if (std::isalnum(*it) || *it == '_') 0095 { 0096 name += *it; 0097 } 0098 else // end of name 0099 { 0100 names_.push_back(name); 0101 name.clear(); 0102 std::ostringstream ss; 0103 ss << '?'; 0104 query_ += ss.str(); 0105 query_ += *it; 0106 state = normal; 0107 0108 } 0109 break; 0110 } 0111 } 0112 0113 if (state == in_name) 0114 { 0115 names_.push_back(name); 0116 std::ostringstream ss; 0117 ss << '?'; 0118 query_ += ss.str(); 0119 } 0120 0121 SQLRETURN cliRC = SQLPrepare(hStmt, const_cast<SQLCHAR *>((const SQLCHAR *) query_.c_str()), SQL_NTS); 0122 if (cliRC!=SQL_SUCCESS) { 0123 throw db2_soci_error("Error while preparing query",cliRC); 0124 } 0125 } 0126 0127 statement_backend::exec_fetch_result 0128 db2_statement_backend::execute(int number ) 0129 { 0130 SQLUINTEGER rows_processed = 0; 0131 SQLRETURN cliRC; 0132 0133 if (hasVectorUseElements) 0134 { 0135 SQLSetStmtAttr(hStmt, SQL_ATTR_PARAMS_PROCESSED_PTR, &rows_processed, 0); 0136 } 0137 0138 // if we are called twice for the same statement we need to close the open 0139 // cursor or an "invalid cursor state" error will occur on execute 0140 cliRC = SQLFreeStmt(hStmt,SQL_CLOSE); 0141 if (cliRC != SQL_SUCCESS) 0142 { 0143 throw db2_soci_error(db2_soci_error::sqlState("Statement execution error",SQL_HANDLE_STMT,hStmt),cliRC); 0144 } 0145 0146 cliRC = SQLExecute(hStmt); 0147 if (cliRC != SQL_SUCCESS && cliRC != SQL_SUCCESS_WITH_INFO && cliRC != SQL_NO_DATA) 0148 { 0149 throw db2_soci_error(db2_soci_error::sqlState("Statement execution error",SQL_HANDLE_STMT,hStmt),cliRC); 0150 } 0151 0152 SQLSMALLINT colCount; 0153 SQLNumResultCols(hStmt, &colCount); 0154 0155 if (number > 0 && colCount > 0) 0156 { 0157 return fetch(number); 0158 } 0159 0160 return ef_success; 0161 } 0162 0163 statement_backend::exec_fetch_result 0164 db2_statement_backend::fetch(int number ) 0165 { 0166 numRowsFetched = 0; 0167 0168 SQLSetStmtAttr(hStmt, SQL_ATTR_ROW_BIND_TYPE, SQL_BIND_BY_COLUMN, 0); 0169 SQLSetStmtAttr(hStmt, SQL_ATTR_ROW_ARRAY_SIZE, db2::int_as_ptr(number), 0); 0170 SQLSetStmtAttr(hStmt, SQL_ATTR_ROWS_FETCHED_PTR, &numRowsFetched, 0); 0171 0172 SQLRETURN cliRC = SQLFetch(hStmt); 0173 0174 if (SQL_NO_DATA == cliRC) 0175 { 0176 return ef_no_data; 0177 } 0178 0179 if (cliRC != SQL_SUCCESS && cliRC != SQL_SUCCESS_WITH_INFO) 0180 { 0181 throw db2_soci_error(db2_soci_error::sqlState("Error while fetching data", SQL_HANDLE_STMT, hStmt), cliRC); 0182 } 0183 0184 return ef_success; 0185 } 0186 0187 long long db2_statement_backend::get_affected_rows() 0188 { 0189 SQLLEN rows; 0190 0191 SQLRETURN cliRC = SQLRowCount(hStmt, &rows); 0192 if (cliRC != SQL_SUCCESS && cliRC != SQL_SUCCESS_WITH_INFO) 0193 { 0194 throw db2_soci_error(db2_soci_error::sqlState("Error while getting affected row count", SQL_HANDLE_STMT, hStmt), cliRC); 0195 } 0196 else if (rows == -1) 0197 { 0198 throw soci_error("Error getting affected row count: statement did not perform an update, insert, delete, or merge"); 0199 } 0200 0201 return rows; 0202 } 0203 0204 int db2_statement_backend::get_number_of_rows() 0205 { 0206 return numRowsFetched; 0207 } 0208 0209 std::string db2_statement_backend::get_parameter_name(int index) const 0210 { 0211 return names_.at(index); 0212 } 0213 0214 std::string db2_statement_backend::rewrite_for_procedure_call( 0215 std::string const &query) 0216 { 0217 return query; 0218 } 0219 0220 int db2_statement_backend::prepare_for_describe() 0221 { 0222 SQLSMALLINT numCols; 0223 SQLNumResultCols(hStmt, &numCols); 0224 return numCols; 0225 } 0226 0227 void db2_statement_backend::describe_column(int colNum, 0228 data_type & type, std::string & columnName ) 0229 { 0230 SQLCHAR colNameBuffer[2048]; 0231 SQLSMALLINT colNameBufferOverflow; 0232 SQLSMALLINT dataType; 0233 SQLULEN colSize; 0234 SQLSMALLINT decDigits; 0235 SQLSMALLINT isNullable; 0236 0237 SQLRETURN cliRC = SQLDescribeCol(hStmt, static_cast<SQLUSMALLINT>(colNum), 0238 colNameBuffer, 2048, 0239 &colNameBufferOverflow, &dataType, 0240 &colSize, &decDigits, &isNullable); 0241 0242 if (cliRC != SQL_SUCCESS) 0243 { 0244 throw db2_soci_error(db2_soci_error::sqlState("Error while describing column",SQL_HANDLE_STMT,hStmt),cliRC); 0245 } 0246 0247 char const *name = reinterpret_cast<char const *>(colNameBuffer); 0248 columnName.assign(name, std::strlen(name)); 0249 0250 switch (dataType) 0251 { 0252 case SQL_TYPE_DATE: 0253 case SQL_TYPE_TIME: 0254 case SQL_TYPE_TIMESTAMP: 0255 type = dt_date; 0256 break; 0257 case SQL_DOUBLE: 0258 case SQL_DECIMAL: 0259 case SQL_REAL: 0260 case SQL_FLOAT: 0261 case SQL_NUMERIC: 0262 type = dt_double; 0263 break; 0264 case SQL_TINYINT: 0265 case SQL_SMALLINT: 0266 case SQL_INTEGER: 0267 type = dt_integer; 0268 break; 0269 case SQL_BIGINT: 0270 type = dt_long_long; 0271 break; 0272 case SQL_CHAR: 0273 case SQL_VARCHAR: 0274 case SQL_LONGVARCHAR: 0275 default: 0276 type = dt_string; 0277 break; 0278 } 0279 } 0280 0281 size_t db2_statement_backend::column_size(int col) { 0282 SQLCHAR colNameBuffer[2048]; 0283 SQLSMALLINT colNameBufferOverflow; 0284 SQLSMALLINT dataType; 0285 SQLULEN colSize; 0286 SQLSMALLINT decDigits; 0287 SQLSMALLINT isNullable; 0288 0289 SQLRETURN cliRC = SQLDescribeCol(hStmt, static_cast<SQLUSMALLINT>(col), 0290 colNameBuffer, 2048, 0291 &colNameBufferOverflow, &dataType, 0292 &colSize, &decDigits, &isNullable); 0293 0294 if (cliRC != SQL_SUCCESS) 0295 { 0296 throw db2_soci_error(db2_soci_error::sqlState("Error while detecting column size",SQL_HANDLE_STMT,hStmt),cliRC); 0297 } 0298 0299 return colSize; 0300 } 0301 0302 db2_standard_into_type_backend * db2_statement_backend::make_into_type_backend() 0303 { 0304 return new db2_standard_into_type_backend(*this); 0305 } 0306 0307 db2_standard_use_type_backend * db2_statement_backend::make_use_type_backend() 0308 { 0309 return new db2_standard_use_type_backend(*this); 0310 } 0311 0312 db2_vector_into_type_backend * 0313 db2_statement_backend::make_vector_into_type_backend() 0314 { 0315 return new db2_vector_into_type_backend(*this); 0316 } 0317 0318 db2_vector_use_type_backend * db2_statement_backend::make_vector_use_type_backend() 0319 { 0320 hasVectorUseElements = true; 0321 return new db2_vector_use_type_backend(*this); 0322 }