src/dbapi/driver/odbc/rpc.cpp

Go to the documentation of this file.
00001 /* $Id: rpc.cpp 118386 2008-01-28 20:30:19Z ssikorsk $
00002  * ===========================================================================
00003  *
00004  *                            PUBLIC DOMAIN NOTICE
00005  *               National Center for Biotechnology Information
00006  *
00007  *  This software/database is a "United States Government Work" under the
00008  *  terms of the United States Copyright Act.  It was written as part of
00009  *  the author's official duties as a United States Government employee and
00010  *  thus cannot be copyrighted.  This software/database is freely available
00011  *  to the public for use. The National Library of Medicine and the U.S.
00012  *  Government have not placed any restriction on its use or reproduction.
00013  *
00014  *  Although all reasonable efforts have been taken to ensure the accuracy
00015  *  and reliability of the software and data, the NLM and the U.S.
00016  *  Government do not and cannot warrant the performance or results that
00017  *  may be obtained by using this software or data. The NLM and the U.S.
00018  *  Government disclaim all warranties, express or implied, including
00019  *  warranties of performance, merchantability or fitness for any particular
00020  *  purpose.
00021  *
00022  *  Please cite the author in any work or product based on this material.
00023  *
00024  * ===========================================================================
00025  *
00026  * Author:  Vladimir Soussov
00027  *
00028  * File Description:  ODBC RPC command
00029  *
00030  */
00031 
00032 #include <ncbi_pch.hpp>
00033 #include <dbapi/driver/odbc/interfaces.hpp>
00034 #include <dbapi/driver/util/numeric_convert.hpp>
00035 #include <dbapi/error_codes.hpp>
00036 
00037 #include <stdio.h>
00038 
00039 #include "odbc_utils.hpp"
00040 
00041 
00042 #define NCBI_USE_ERRCODE_X   Dbapi_Odbc_Cmds
00043 
00044 BEGIN_NCBI_SCOPE
00045 
00046 
00047 /////////////////////////////////////////////////////////////////////////////
00048 //
00049 //  CODBC_RPCCmd::
00050 //
00051 
00052 CODBC_RPCCmd::CODBC_RPCCmd(CODBC_Connection& conn,
00053                            const string& proc_name) :
00054     CStatementBase(conn),
00055     impl::CBaseCmd(conn, proc_name),
00056     m_Res(0)
00057 {
00058     string extra_msg = "Procedure Name: " + proc_name;
00059     SetDbgInfo( extra_msg );
00060 
00061     return;
00062 }
00063 
00064 
00065 CDBParams& 
00066 CODBC_RPCCmd::GetBindParams(void)
00067 {
00068     if (m_InParams.get() == NULL) {
00069         m_InParams.reset(new impl::CRowInfo_SP_SQL_Server(
00070                     GetQuery(), 
00071                     GetConnImpl(), 
00072                     GetBindParamsImpl()
00073                     )
00074                 );
00075     }
00076 
00077     return *m_InParams;
00078 }
00079 
00080 
00081 bool CODBC_RPCCmd::Send()
00082 {
00083     Cancel();
00084 
00085     SetHasFailed(false);
00086     m_HasStatus = false;
00087 
00088     // make a language command
00089     string main_exec_query("declare @STpROCrETURNsTATUS int;\nexec @STpROCrETURNsTATUS=");
00090     main_exec_query += GetQuery();
00091     string param_result_query;
00092 
00093     CMemPot bindGuard;
00094     string q_str;
00095 
00096     if(GetBindParamsImpl().NofParams() > 0) {
00097         SQLLEN* indicator = (SQLLEN*)
00098                 bindGuard.Alloc(GetBindParamsImpl().NofParams() * sizeof(SQLLEN));
00099 
00100         if (!x_AssignParams(q_str, main_exec_query, param_result_query,
00101                           bindGuard, indicator)) {
00102             ResetParams();
00103             SetHasFailed();
00104 
00105             string err_message = "Cannot assign params." + GetDbgInfo();
00106             DATABASE_DRIVER_ERROR( err_message, 420003 );
00107         }
00108     }
00109 
00110    if(NeedToRecompile()) main_exec_query += " with recompile";
00111 
00112    q_str += main_exec_query + ";\nselect STpROCrETURNsTATUS=@STpROCrETURNsTATUS";
00113    if(!param_result_query.empty()) {
00114        q_str += ";\nselect " + param_result_query;
00115    }
00116 
00117     switch(SQLExecDirect(GetHandle(), CODBCString(q_str, GetClientEncoding()), SQL_NTS)) {
00118     case SQL_SUCCESS:
00119         m_HasMoreResults = true;
00120         break;
00121 
00122     case SQL_NO_DATA:
00123         m_HasMoreResults = true; /* this is a bug in SQLExecDirect it returns SQL_NO_DATA if
00124                                status result is the only result of RPC */
00125         m_RowCount = 0;
00126         break;
00127 
00128     case SQL_ERROR:
00129         ReportErrors();
00130         ResetParams();
00131         SetHasFailed();
00132         {
00133             string err_message = "SQLExecDirect failed." + GetDbgInfo();
00134             DATABASE_DRIVER_ERROR( err_message, 420001 );
00135         }
00136 
00137     case SQL_SUCCESS_WITH_INFO:
00138         ReportErrors();
00139         m_HasMoreResults = true;
00140         break;
00141 
00142     case SQL_STILL_EXECUTING:
00143         ReportErrors();
00144         ResetParams();
00145         SetHasFailed();
00146         {
00147             string err_message = "Some other query is executing on this connection." +
00148                 GetDbgInfo();
00149             DATABASE_DRIVER_ERROR( err_message, 420002 );
00150         }
00151 
00152     case SQL_INVALID_HANDLE:
00153         SetHasFailed();
00154         {
00155             string err_message = "The statement handler is invalid (memory corruption suspected)." +
00156                 GetDbgInfo();
00157             DATABASE_DRIVER_ERROR( err_message, 420004 );
00158         }
00159 
00160     default:
00161         ReportErrors();
00162         ResetParams();
00163         SetHasFailed();
00164         {
00165             string err_message = "Unexpected error." + GetDbgInfo();
00166             DATABASE_DRIVER_ERROR( err_message, 420005 );
00167         }
00168 
00169     }
00170 
00171     SetWasSent();
00172     return true;
00173 }
00174 
00175 
00176 bool CODBC_RPCCmd::Cancel()
00177 {
00178     if (WasSent()) {
00179         if (m_Res) {
00180             delete m_Res;
00181             m_Res = 0;
00182         }
00183 
00184         SetWasSent(false);
00185 
00186         if ( !Close() ) {
00187             return false;
00188         }
00189 
00190         ResetParams();
00191         // GetQuery().erase();
00192     }
00193 
00194     return true;
00195 }
00196 
00197 
00198 CDB_Result* CODBC_RPCCmd::Result()
00199 {
00200     enum {eNameStrLen = 64};
00201 
00202     if (m_Res) {
00203         delete m_Res;
00204         m_Res = 0;
00205         m_HasMoreResults = xCheck4MoreResults();
00206     }
00207 
00208     if ( !WasSent() ) {
00209         string err_message = "A command has to be sent first." + GetDbgInfo();
00210         DATABASE_DRIVER_ERROR( err_message, 420010 );
00211     }
00212 
00213     if(!m_HasMoreResults) {
00214         SetWasSent(false);
00215         return 0;
00216     }
00217 
00218     SQLSMALLINT nof_cols = 0;
00219     odbc::TChar buffer[eNameStrLen];
00220 
00221     while(m_HasMoreResults) {
00222         CheckSIE(SQLNumResultCols(GetHandle(), &nof_cols),
00223                  "SQLNumResultCols failed", 420011);
00224 
00225         if(nof_cols < 1) { // no data in this result set
00226             SQLLEN rc;
00227 
00228             CheckSIE(SQLRowCount(GetHandle(), &rc),
00229                      "SQLRowCount failed", 420013);
00230 
00231             m_RowCount = rc;
00232             m_HasMoreResults = xCheck4MoreResults();
00233             continue;
00234         }
00235 
00236         if(nof_cols == 1) { // it could be a status result
00237             SQLSMALLINT l;
00238 
00239             CheckSIE(SQLColAttribute(GetHandle(),
00240                                      1,
00241                                      SQL_DESC_LABEL,
00242                                      buffer,
00243                                      sizeof(buffer),
00244                                      &l,
00245                                      0),
00246                      "SQLColAttribute failed", 420015);
00247 
00248             if(util::strcmp(buffer, _T("STpROCrETURNsTATUS")) == 0) {//this is a status result
00249                 m_HasStatus = true;
00250                 m_Res = new CODBC_StatusResult(*this);
00251             }
00252         }
00253         if(!m_Res) {
00254             if(m_HasStatus) {
00255                 m_HasStatus = false;
00256                 m_Res = new CODBC_ParamResult(*this, nof_cols);
00257             }
00258             else {
00259                 m_Res = new CODBC_RowResult(*this, nof_cols, &m_RowCount);
00260             }
00261         }
00262         return Create_Result(*m_Res);
00263     }
00264 
00265     SetWasSent(false);
00266     return 0;
00267 }
00268 
00269 
00270 bool CODBC_RPCCmd::HasMoreResults() const
00271 {
00272     return m_HasMoreResults;
00273 }
00274 
00275 
00276 int CODBC_RPCCmd::RowCount() const
00277 {
00278     return static_cast<int>(m_RowCount);
00279 }
00280 
00281 
00282 CODBC_RPCCmd::~CODBC_RPCCmd()
00283 {
00284     try {
00285         DetachInterface();
00286 
00287         GetConnection().DropCmd(*this);
00288 
00289         Cancel();
00290     }
00291     NCBI_CATCH_ALL_X( 5, NCBI_CURRENT_FUNCTION )
00292 }
00293 
00294 
00295 bool CODBC_RPCCmd::x_AssignParams(string& cmd, string& q_exec, string& q_select,
00296                                    CMemPot& bind_guard, SQLLEN* indicator)
00297 {
00298     char p_nm[16];
00299     // check if we do have a named parameters (first named - all named)
00300     bool param_named = !GetBindParamsImpl().GetParamName(0).empty();
00301 
00302     for (unsigned int n = 0; n < GetBindParamsImpl().NofParams(); n++) {
00303         if(GetBindParamsImpl().GetParamStatus(n) == 0) continue;
00304         const string& name  =  GetBindParamsImpl().GetParamName(n);
00305         CDB_Object&   param = *GetBindParamsImpl().GetParam(n);
00306 
00307         if (!x_BindParam_ODBC(param, bind_guard, indicator, n)) {
00308             return false;
00309         }
00310 
00311         q_exec += n ? ',':' ';
00312 
00313         const string type = Type2String(param);
00314         if(!param_named) {
00315             sprintf(p_nm, "@pR%d", n);
00316             q_exec += p_nm;
00317             cmd += "declare ";
00318             cmd += p_nm;
00319             cmd += ' ';
00320             cmd += type;
00321             cmd += ";select ";
00322             cmd += p_nm;
00323             cmd += " = ?;";
00324         }
00325         else {
00326             q_exec += name+'='+name;
00327             cmd += "declare " + name + ' ' + type + ";select " + name + " = ?;";
00328         }
00329 
00330         if(param.IsNULL()) {
00331             indicator[n] = SQL_NULL_DATA;
00332         }
00333 
00334         if ((GetBindParamsImpl().GetParamStatus(n) & impl::CDB_Params::fOutput) != 0) {
00335             q_exec += " output";
00336             const char* p_name = param_named? name.c_str() : p_nm;
00337             if(!q_select.empty()) q_select += ',';
00338             q_select.append(p_name+1);
00339             q_select += '=';
00340             q_select += p_name;
00341         }
00342     }
00343     return true;
00344 }
00345 
00346 bool CODBC_RPCCmd::xCheck4MoreResults()
00347 {
00348 //     int rc = CheckSIE(SQLMoreResults(GetHandle()),
00349 //              "SQLMoreResults failed", 420015);
00350 //
00351 //     return (rc == SQL_SUCCESS_WITH_INFO || rc == SQL_SUCCESS);
00352 
00353     switch(SQLMoreResults(GetHandle())) {
00354     case SQL_SUCCESS_WITH_INFO: ReportErrors();
00355     case SQL_SUCCESS:           return true;
00356     case SQL_NO_DATA:           return false;
00357     case SQL_ERROR:
00358         ReportErrors();
00359         {
00360             string err_message = "SQLMoreResults failed." + GetDbgInfo();
00361             DATABASE_DRIVER_ERROR( err_message, 420014 );
00362         }
00363     default:
00364         {
00365             string err_message = "SQLMoreResults failed (memory corruption suspected)." +
00366                 GetDbgInfo();
00367             DATABASE_DRIVER_ERROR( err_message, 420015 );
00368         }
00369     }
00370 }
00371 
00372 END_NCBI_SCOPE
00373 
00374 
00375 
00376 

Generated on Wed Dec 9 04:15:23 2009 for NCBI C++ ToolKit by  doxygen 1.4.6
Modified on Wed Dec 09 08:17:56 2009 by modify_doxy.py rev. 173732