// // Copyright (C) 2004-2006 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) // #include "soci.h" #include "soci-oracle.h" #include "error.h" #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; OracleStatementBackEnd::OracleStatementBackEnd(OracleSessionBackEnd &session) : session_(session), stmtp_(NULL), boundByName_(false), boundByPos_(false) { } void OracleStatementBackEnd::alloc() { sword res = OCIHandleAlloc(session_.envhp_, reinterpret_cast(&stmtp_), OCI_HTYPE_STMT, 0, 0); if (res != OCI_SUCCESS) { throw SOCIError("Cannot allocate statement handle"); } } void OracleStatementBackEnd::cleanUp() { // deallocate statement handle if (stmtp_ != NULL) { OCIHandleFree(stmtp_, OCI_HTYPE_STMT); stmtp_ = NULL; } boundByName_ = false; boundByPos_ = false; } void OracleStatementBackEnd::prepare(std::string const &query) { 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) { throwOracleSOCIError(res, session_.errhp_); } } StatementBackEnd::execFetchResult OracleStatementBackEnd::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 eSuccess; } else if (res == OCI_NO_DATA) { return eNoData; } else { throwOracleSOCIError(res, session_.errhp_); return eNoData; // unreachable dummy return to please the compiler } } StatementBackEnd::execFetchResult OracleStatementBackEnd::fetch(int number) { sword res = OCIStmtFetch(stmtp_, session_.errhp_, static_cast(number), OCI_FETCH_NEXT, OCI_DEFAULT); if (res == OCI_SUCCESS || res == OCI_SUCCESS_WITH_INFO) { return eSuccess; } else if (res == OCI_NO_DATA) { return eNoData; } else { throwOracleSOCIError(res, session_.errhp_); return eNoData; // unreachable dummy return to please the compiler } } int OracleStatementBackEnd::getNumberOfRows() { 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) { throwOracleSOCIError(res, session_.errhp_); } return rows; } std::string OracleStatementBackEnd::rewriteForProcedureCall( std::string const &query) { std::string newQuery("begin "); newQuery += query; newQuery += "; end;"; return newQuery; } int OracleStatementBackEnd::prepareForDescribe() { sword res = OCIStmtExecute(session_.svchp_, stmtp_, session_.errhp_, 1, 0, 0, 0, OCI_DESCRIBE_ONLY); if (res != OCI_SUCCESS) { throwOracleSOCIError(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) { throwOracleSOCIError(res, session_.errhp_); } return cols; } void OracleStatementBackEnd::describeColumn(int colNum, eDataType &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) { throwOracleSOCIError(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) { throwOracleSOCIError(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) { throwOracleSOCIError(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) { throwOracleSOCIError(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) { throwOracleSOCIError(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) { throwOracleSOCIError(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 = eString; break; case SQLT_NUM: if (scale > 0) { type = eDouble; } else if (precision < std::numeric_limits::digits10) { type = eInteger; } else { type = eUnsignedLong; } break; case SQLT_DAT: type = eDate; break; } } std::size_t OracleStatementBackEnd::columnSize(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) { throwOracleSOCIError(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) { throwOracleSOCIError(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) { throwOracleSOCIError(res, session_.errhp_); } return static_cast(colSize); }