// // Copyright (C) 2004-2007 Maciej Sobczak, Stephen Hutton // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #define soci_ORACLE_SOURCE #include "soci-oracle.h" #include "error.h" #include #include #include #include #include #include #include #ifdef _MSC_VER #pragma warning(disable:4355) #endif using namespace soci; using namespace soci::details; using namespace soci::details::oracle; oracle_statement_backend::oracle_statement_backend(oracle_session_backend &session) : session_(session), stmtp_(NULL), boundByName_(false), boundByPos_(false), noData_(false) { } void oracle_statement_backend::alloc() { sword res = OCIHandleAlloc(session_.envhp_, reinterpret_cast(&stmtp_), OCI_HTYPE_STMT, 0, 0); if (res != OCI_SUCCESS) { throw soci_error("Cannot allocate statement handle"); } } void oracle_statement_backend::clean_up() { // deallocate statement handle if (stmtp_ != NULL) { OCIHandleFree(stmtp_, OCI_HTYPE_STMT); stmtp_ = NULL; } boundByName_ = false; boundByPos_ = false; } void oracle_statement_backend::prepare(std::string const &query, statement_type /* eType */) { sb4 stmtLen = static_cast(query.size()); sword res = OCIStmtPrepare(stmtp_, session_.errhp_, reinterpret_cast(const_cast(query.c_str())), stmtLen, OCI_V7_SYNTAX, OCI_DEFAULT); if (res != OCI_SUCCESS) { throw_oracle_soci_error(res, session_.errhp_); } } statement_backend::exec_fetch_result oracle_statement_backend::execute(int number) { sword res = OCIStmtExecute(session_.svchp_, stmtp_, session_.errhp_, static_cast(number), 0, 0, 0, OCI_DEFAULT); if (res == OCI_SUCCESS || res == OCI_SUCCESS_WITH_INFO) { return ef_success; } else if (res == OCI_NO_DATA) { noData_ = true; return ef_no_data; } else { throw_oracle_soci_error(res, session_.errhp_); return ef_no_data; // unreachable dummy return to please the compiler } } statement_backend::exec_fetch_result oracle_statement_backend::fetch(int number) { if (noData_) { return ef_no_data; } sword res = OCIStmtFetch(stmtp_, session_.errhp_, static_cast(number), OCI_FETCH_NEXT, OCI_DEFAULT); if (res == OCI_SUCCESS || res == OCI_SUCCESS_WITH_INFO) { return ef_success; } else if (res == OCI_NO_DATA) { noData_ = true; return ef_no_data; } else { throw_oracle_soci_error(res, session_.errhp_); return ef_no_data; // unreachable dummy return to please the compiler } } int oracle_statement_backend::get_number_of_rows() { int rows; sword res = OCIAttrGet(static_cast(stmtp_), static_cast(OCI_HTYPE_STMT), static_cast(&rows), 0, static_cast(OCI_ATTR_ROWS_FETCHED), session_.errhp_); if (res != OCI_SUCCESS) { throw_oracle_soci_error(res, session_.errhp_); } return rows; } std::string oracle_statement_backend::rewrite_for_procedure_call( std::string const &query) { std::string newQuery("begin "); newQuery += query; newQuery += "; end;"; return newQuery; } int oracle_statement_backend::prepare_for_describe() { sword res = OCIStmtExecute(session_.svchp_, stmtp_, session_.errhp_, 1, 0, 0, 0, OCI_DESCRIBE_ONLY); if (res != OCI_SUCCESS) { throw_oracle_soci_error(res, session_.errhp_); } int cols; res = OCIAttrGet(static_cast(stmtp_), static_cast(OCI_HTYPE_STMT), static_cast(&cols), 0, static_cast(OCI_ATTR_PARAM_COUNT), session_.errhp_); if (res != OCI_SUCCESS) { throw_oracle_soci_error(res, session_.errhp_); } return cols; } void oracle_statement_backend::describe_column(int colNum, data_type &type, std::string &columnName) { int size; int precision; int scale; ub2 dbtype; text* dbname; ub4 nameLength; ub2 dbsize; sb2 dbprec; ub1 dbscale; //sb2 in some versions of Oracle? // Get the column handle OCIParam* colhd; sword res = OCIParamGet(reinterpret_cast(stmtp_), static_cast(OCI_HTYPE_STMT), reinterpret_cast(session_.errhp_), reinterpret_cast(&colhd), static_cast(colNum)); if (res != OCI_SUCCESS) { throw_oracle_soci_error(res, session_.errhp_); } // Get the column name res = OCIAttrGet(reinterpret_cast(colhd), static_cast(OCI_DTYPE_PARAM), reinterpret_cast(&dbname), reinterpret_cast(&nameLength), static_cast(OCI_ATTR_NAME), reinterpret_cast(session_.errhp_)); if (res != OCI_SUCCESS) { throw_oracle_soci_error(res, session_.errhp_); } // Get the column type res = OCIAttrGet(reinterpret_cast(colhd), static_cast(OCI_DTYPE_PARAM), reinterpret_cast(&dbtype), 0, static_cast(OCI_ATTR_DATA_TYPE), reinterpret_cast(session_.errhp_)); if (res != OCI_SUCCESS) { throw_oracle_soci_error(res, session_.errhp_); } // get the data size res = OCIAttrGet(reinterpret_cast(colhd), static_cast(OCI_DTYPE_PARAM), reinterpret_cast(&dbsize), 0, static_cast(OCI_ATTR_DATA_SIZE), reinterpret_cast(session_.errhp_)); if (res != OCI_SUCCESS) { throw_oracle_soci_error(res, session_.errhp_); } // get the precision res = OCIAttrGet(reinterpret_cast(colhd), static_cast(OCI_DTYPE_PARAM), reinterpret_cast(&dbprec), 0, static_cast(OCI_ATTR_PRECISION), reinterpret_cast(session_.errhp_)); if (res != OCI_SUCCESS) { throw_oracle_soci_error(res, session_.errhp_); } // get the scale res = OCIAttrGet(reinterpret_cast(colhd), static_cast(OCI_DTYPE_PARAM), reinterpret_cast(&dbscale), 0, static_cast(OCI_ATTR_SCALE), reinterpret_cast(session_.errhp_)); if (res != OCI_SUCCESS) { throw_oracle_soci_error(res, session_.errhp_); } columnName.assign(dbname, dbname + nameLength); size = static_cast(dbsize); precision = static_cast(dbprec); scale = static_cast(dbscale); switch (dbtype) { case SQLT_CHR: case SQLT_AFC: type = dt_string; break; case SQLT_NUM: if (scale > 0) { type = dt_double; } else if (precision < std::numeric_limits::digits10) { type = dt_integer; } else { type = dt_long_long; } break; case SQLT_DAT: type = dt_date; break; } } std::size_t oracle_statement_backend::column_size(int position) { // Note: we may want to optimize so that the OCI_DESCRIBE_ONLY call // happens only once per statement. // Possibly use existing statement::describe() / make column prop // access lazy at same time int colSize(0); sword res = OCIStmtExecute(session_.svchp_, stmtp_, session_.errhp_, 1, 0, 0, 0, OCI_DESCRIBE_ONLY); if (res != OCI_SUCCESS) { throw_oracle_soci_error(res, session_.errhp_); } // Get The Column Handle OCIParam* colhd; res = OCIParamGet(reinterpret_cast(stmtp_), static_cast(OCI_HTYPE_STMT), reinterpret_cast(session_.errhp_), reinterpret_cast(&colhd), static_cast(position)); if (res != OCI_SUCCESS) { throw_oracle_soci_error(res, session_.errhp_); } // Get The Data Size res = OCIAttrGet(reinterpret_cast(colhd), static_cast(OCI_DTYPE_PARAM), reinterpret_cast(&colSize), 0, static_cast(OCI_ATTR_DATA_SIZE), reinterpret_cast(session_.errhp_)); if (res != OCI_SUCCESS) { throw_oracle_soci_error(res, session_.errhp_); } return static_cast(colSize); }