rpc.cpp
上传用户:yhdzpy8989
上传日期:2007-06-13
资源大小:13604k
文件大小:17k
源码类别:

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: rpc.cpp,v $
  4.  * PRODUCTION Revision 1000.1  2004/06/01 19:20:58  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.12
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /* $Id: rpc.cpp,v 1000.1 2004/06/01 19:20:58 gouriano Exp $
  10.  * ===========================================================================
  11.  *
  12.  *                            PUBLIC DOMAIN NOTICE
  13.  *               National Center for Biotechnology Information
  14.  *
  15.  *  This software/database is a "United States Government Work" under the
  16.  *  terms of the United States Copyright Act.  It was written as part of
  17.  *  the author's official duties as a United States Government employee and
  18.  *  thus cannot be copyrighted.  This software/database is freely available
  19.  *  to the public for use. The National Library of Medicine and the U.S.
  20.  *  Government have not placed any restriction on its use or reproduction.
  21.  *
  22.  *  Although all reasonable efforts have been taken to ensure the accuracy
  23.  *  and reliability of the software and data, the NLM and the U.S.
  24.  *  Government do not and cannot warrant the performance or results that
  25.  *  may be obtained by using this software or data. The NLM and the U.S.
  26.  *  Government disclaim all warranties, express or implied, including
  27.  *  warranties of performance, merchantability or fitness for any particular
  28.  *  purpose.
  29.  *
  30.  *  Please cite the author in any work or product based on this material.
  31.  *
  32.  * ===========================================================================
  33.  *
  34.  * Author:  Vladimir Soussov
  35.  *
  36.  * File Description:  TDS RPC command
  37.  *
  38.  */
  39.  
  40. #include <ncbi_pch.hpp>
  41. #include <dbapi/driver/ftds/interfaces.hpp>
  42. #include <dbapi/driver/util/numeric_convert.hpp>
  43. BEGIN_NCBI_SCOPE
  44. /////////////////////////////////////////////////////////////////////////////
  45. //
  46. //  CTDS_RPCCmd::
  47. //
  48. CTDS_RPCCmd::CTDS_RPCCmd(CTDS_Connection* con, DBPROCESS* cmd,
  49.                          const string& proc_name, unsigned int nof_params) :
  50.     m_Connect(con), m_Cmd(cmd), m_Query(proc_name), m_Params(nof_params),
  51.     m_WasSent(false), m_HasFailed(false), m_Recompile(false), m_Res(0),
  52.     m_RowCount(-1), m_Status(0)
  53. {
  54.     return;
  55. }
  56. bool CTDS_RPCCmd::BindParam(const string& param_name,
  57.                             CDB_Object* param_ptr, bool out_param)
  58. {
  59.     return m_Params.BindParam(CDB_Params::kNoParamNumber, param_name,
  60.                               param_ptr, out_param);
  61. }
  62. bool CTDS_RPCCmd::SetParam(const string& param_name,
  63.                            CDB_Object* param_ptr, bool out_param)
  64. {
  65.     return m_Params.SetParam(CDB_Params::kNoParamNumber, param_name,
  66.                              param_ptr, out_param);
  67. }
  68. bool CTDS_RPCCmd::Send()
  69. {
  70.     if (m_WasSent)
  71.         Cancel();
  72.     m_HasFailed = false;
  73.     if (!x_AssignOutputParams()) {
  74.         dbfreebuf(m_Cmd);
  75.         m_HasFailed = true;
  76.         throw CDB_ClientEx(eDB_Error, 221001, "CTDS_RPCCmd::Send",
  77.                            "cannot assign the output params");
  78.     }
  79.     string cmd= "execute " + m_Query;
  80.     if (dbcmd(m_Cmd, (char*)(cmd.c_str())) != SUCCEED) {
  81.         dbfreebuf(m_Cmd);
  82.         m_HasFailed = true;
  83.         throw CDB_ClientEx(eDB_Fatal, 221002, "CTDS_RPCCmd::Send",
  84.                            "dbcmd failed");
  85.     }
  86.     if (!x_AssignParams()) {
  87.         m_HasFailed = true;
  88.         throw CDB_ClientEx(eDB_Error, 221003, "CTDS_RPCCmd::Send",
  89.                            "can not assign the params");
  90.     }
  91.     m_Connect->TDS_SetTimeout();
  92.     if (dbsqlsend(m_Cmd) != SUCCEED) {
  93.         m_HasFailed = true;
  94.         throw CDB_ClientEx(eDB_Error, 221005, "CTDS_RPCCmd::Send",
  95.                            "dbsqlsend failed");
  96.     }
  97.     m_WasSent = true;
  98.     m_Status = 0;
  99.     return true;
  100. }
  101. bool CTDS_RPCCmd::WasSent() const
  102. {
  103.     return m_WasSent;
  104. }
  105. bool CTDS_RPCCmd::Cancel()
  106. {
  107.     if (m_WasSent) {
  108.         if (m_Res) {
  109.             delete m_Res;
  110.             m_Res = 0;
  111.         }
  112.         m_WasSent = false;
  113.         return dbcancel(m_Cmd) == SUCCEED;
  114.     }
  115.     // m_Query.erase();
  116.     return true;
  117. }
  118. bool CTDS_RPCCmd::WasCanceled() const
  119. {
  120.     return !m_WasSent;
  121. }
  122. CDB_Result* CTDS_RPCCmd::Result()
  123. {
  124.     if (m_Res) {
  125.         if(m_RowCount < 0) {
  126.             m_RowCount = DBCOUNT(m_Cmd);
  127.         }
  128.         delete m_Res;
  129.         m_Res = 0;
  130.     }
  131.     if (!m_WasSent) {
  132.         throw CDB_ClientEx(eDB_Error, 221010, "CTDS_RPCCmd::Result",
  133.                            "you have to send a command first");
  134.     }
  135.     if (m_Status == 0) {
  136.         m_Status = 1;
  137.         if (dbsqlok(m_Cmd) != SUCCEED) {
  138.             m_WasSent = false;
  139.             m_HasFailed = true;
  140.             throw CDB_ClientEx(eDB_Error, 221011, "CTDS_RPCCmd::Result",
  141.                                "dbsqlok failed");
  142.         }
  143.     }
  144.     if ((m_Status & 0x10) != 0) { // we do have a compute result
  145.         m_Res = new CTDS_ComputeResult(m_Cmd, &m_Status);
  146.         m_RowCount = 1;
  147.         return Create_Result(*m_Res);
  148.     }
  149.     while ((m_Status & 0x1) != 0) {
  150.         switch (dbresults(m_Cmd)) {
  151.         case SUCCEED:
  152.             if (DBCMDROW(m_Cmd) == SUCCEED) { // we may get rows in this result
  153.                 m_Res = new CTDS_RowResult(m_Cmd, &m_Status);
  154.                 m_RowCount = -1;
  155.                 return Create_Result(*m_Res);
  156.             } else {
  157.                 m_RowCount = DBCOUNT(m_Cmd);
  158.                 continue;
  159.             }
  160.         case NO_MORE_RESULTS:
  161.             m_Status = 2;
  162.             break;
  163.         default:
  164.             m_HasFailed = true;
  165.             throw CDB_ClientEx(eDB_Warning, 221016, "CTDS_RPCCmd::Result",
  166.                                "error encountered in command execution");
  167.         }
  168.         break;
  169.     }
  170.     // we've done with the row results at this point
  171.     // let's look at return parameters and ret status
  172.     if (m_Status == 2) {
  173.         m_Status = 4;
  174.         int n = dbnumrets(m_Cmd);
  175.         if (n > 0) {
  176.             m_Res = new CTDS_ParamResult(m_Cmd, n);
  177.             m_RowCount = 1;
  178.             return Create_Result(*m_Res);
  179.         }
  180.     }
  181.     if (m_Status == 4) {
  182.         m_Status = 6;
  183.         if (dbhasretstat(m_Cmd)) {
  184.             m_Res = new CTDS_StatusResult(m_Cmd);
  185.             m_RowCount = 1;
  186.             return Create_Result(*m_Res);
  187.         }
  188.     }
  189.     m_WasSent = false;
  190.     return 0;
  191. }
  192. bool CTDS_RPCCmd::HasMoreResults() const
  193. {
  194.     return m_WasSent;
  195. }
  196. void CTDS_RPCCmd::DumpResults()
  197. {
  198.     CDB_Result* dbres;
  199.     while(m_WasSent) {
  200.         dbres= Result();
  201.         if(dbres) {
  202.             if(m_Connect->m_ResProc) {
  203.                 m_Connect->m_ResProc->ProcessResult(*dbres);
  204.             }
  205.             else {
  206.                 while(dbres->Fetch());
  207.             }
  208.             delete dbres;
  209.         }
  210.     }
  211. }
  212. bool CTDS_RPCCmd::HasFailed() const
  213. {
  214.     return m_HasFailed;
  215. }
  216. int CTDS_RPCCmd::RowCount() const
  217. {
  218.     return (m_RowCount < 0)? DBCOUNT(m_Cmd) : m_RowCount;
  219. }
  220. void CTDS_RPCCmd::SetRecompile(bool recompile)
  221. {
  222.     m_Recompile = recompile;
  223. }
  224. void CTDS_RPCCmd::Release()
  225. {
  226.     m_BR = 0;
  227.     if (m_WasSent) {
  228.         Cancel();
  229.         m_WasSent = false;
  230.     }
  231.     m_Connect->DropCmd(*this);
  232.     delete this;
  233. }
  234. CTDS_RPCCmd::~CTDS_RPCCmd()
  235. {
  236.     if (m_BR)
  237.         *m_BR = 0;
  238.     if (m_WasSent)
  239.         Cancel();
  240. }
  241. bool CTDS_RPCCmd::x_AddParamValue(string& cmd, const CDB_Object& param)
  242. {
  243.     static const char s_hexnum[] = "0123456789ABCDEF";
  244.     char val_buffer[16*1024];
  245.     if (!param.IsNULL()) {
  246.         switch (param.GetType()) {
  247.         case eDB_Int: {
  248.             const CDB_Int& val = dynamic_cast<const CDB_Int&> (param);
  249.             sprintf(val_buffer, "%dn", val.Value());
  250.             break;
  251.         }
  252.         case eDB_SmallInt: {
  253.             const CDB_SmallInt& val = dynamic_cast<const CDB_SmallInt&>(param);
  254.             sprintf(val_buffer, "%dn", (int) val.Value());
  255.             break;
  256.         }
  257.         case eDB_TinyInt: {
  258.             const CDB_TinyInt& val = dynamic_cast<const CDB_TinyInt&> (param);
  259.             sprintf(val_buffer, "%dn", (int) val.Value());
  260.             break;
  261.         }
  262.         case eDB_BigInt: {
  263.             const CDB_BigInt& val = dynamic_cast<const CDB_BigInt&> (param);
  264.             sprintf(val_buffer, "%lldn", val.Value());
  265.             break;
  266.         }
  267.         case eDB_Char: {
  268.             const CDB_Char& val = dynamic_cast<const CDB_Char&> (param);
  269.             const char* c = val.Value(); // No more than 255 chars
  270.             size_t i = 0;
  271.             val_buffer[i++] = ''';
  272.             while (*c) {
  273.                 if (*c == ''')
  274.                     val_buffer[i++] = ''';
  275.                 val_buffer[i++] = *c++;
  276.             }
  277.             val_buffer[i++] = ''';
  278.             val_buffer[i++] = 'n';
  279.             val_buffer[i] = '';
  280.             break;
  281.         }
  282.         case eDB_VarChar: {
  283.             const CDB_VarChar& val = dynamic_cast<const CDB_VarChar&> (param);
  284.             const char* c = val.Value();
  285.             size_t i = 0;
  286.             val_buffer[i++] = ''';
  287.             while (*c) {
  288.                 if (*c == ''')
  289.                     val_buffer[i++] = ''';
  290.                 val_buffer[i++] = *c++;
  291.             }
  292.             val_buffer[i++] = ''';
  293.             val_buffer[i++] = 'n';
  294.             val_buffer[i] = '';
  295.             break;
  296.         }
  297.         case eDB_LongChar: {
  298.             const CDB_LongChar& val = dynamic_cast<const CDB_LongChar&> (param);
  299.             const char* c = val.Value();
  300.             size_t i = 0;
  301.             val_buffer[i++] = ''';
  302.             while (*c && (i < sizeof(val_buffer) - 4)) {
  303.                 if (*c == ''')
  304.                     val_buffer[i++] = ''';
  305.                 val_buffer[i++] = *c++;
  306.             }
  307. if(*c != '') return false;
  308.             val_buffer[i++] = ''';
  309.             val_buffer[i++] = 'n';
  310.             val_buffer[i] = '';
  311.             break;
  312.         }
  313.         case eDB_Binary: {
  314.             const CDB_Binary& val = dynamic_cast<const CDB_Binary&> (param);
  315.             const unsigned char* c = (const unsigned char*) val.Value();
  316.             size_t i = 0, size = val.Size();
  317.             val_buffer[i++] = '0';
  318.             val_buffer[i++] = 'x';
  319.             for (size_t j = 0; j < size; j++) {
  320.                 val_buffer[i++] = s_hexnum[c[j] >> 4];
  321.                 val_buffer[i++] = s_hexnum[c[j] & 0x0F];
  322.             }
  323.             val_buffer[i++] = 'n';
  324.             val_buffer[i++] = '';
  325.             break;
  326.         }
  327.         case eDB_VarBinary: {
  328.             const CDB_VarBinary& val =
  329.                 dynamic_cast<const CDB_VarBinary&> (param);
  330.             const unsigned char* c = (const unsigned char*) val.Value();
  331.             size_t i = 0, size = val.Size();
  332.             val_buffer[i++] = '0';
  333.             val_buffer[i++] = 'x';
  334.             for (size_t j = 0; j < size; j++) {
  335.                 val_buffer[i++] = s_hexnum[c[j] >> 4];
  336.                 val_buffer[i++] = s_hexnum[c[j] & 0x0F];
  337.             }
  338.             val_buffer[i++] = 'n';
  339.             val_buffer[i++] = '';
  340.             break;
  341.         }
  342.         case eDB_LongBinary: {
  343.             const CDB_LongBinary& val =
  344.                 dynamic_cast<const CDB_LongBinary&> (param);
  345.             const unsigned char* c = (const unsigned char*) val.Value();
  346.             size_t i = 0, size = val.DataSize();
  347. if(size*2 > sizeof(val_buffer) - 4) return false;
  348.             val_buffer[i++] = '0';
  349.             val_buffer[i++] = 'x';
  350.             for (size_t j = 0; j < size; j++) {
  351.                 val_buffer[i++] = s_hexnum[c[j] >> 4];
  352.                 val_buffer[i++] = s_hexnum[c[j] & 0x0F];
  353.             }
  354.             val_buffer[i++] = 'n';
  355.             val_buffer[i++] = '';
  356.             break;
  357.         }
  358.         case eDB_Float: {
  359.             const CDB_Float& val = dynamic_cast<const CDB_Float&> (param);
  360.             sprintf(val_buffer, "%En", (double) val.Value());
  361.             break;
  362.         }
  363.         case eDB_Double: {
  364.             const CDB_Double& val = dynamic_cast<const CDB_Double&> (param);
  365.             sprintf(val_buffer, "%En", val.Value());
  366.             break;
  367.         }
  368.         case eDB_SmallDateTime: {
  369.             const CDB_SmallDateTime& val =
  370.                 dynamic_cast<const CDB_SmallDateTime&> (param);
  371.             sprintf(val_buffer, "'%s'n",
  372.     val.Value().AsString("M/D/Y h:m").c_str());
  373.             break;
  374.         }
  375.         case eDB_DateTime: {
  376.             const CDB_DateTime& val =
  377.                 dynamic_cast<const CDB_DateTime&> (param);
  378.             sprintf(val_buffer, "'%s:%.3d'n",
  379.     val.Value().AsString("M/D/Y h:m:s").c_str(),
  380.     (int)(val.Value().NanoSecond()/1000000));
  381.             break;
  382.         }
  383.         default:
  384.             return false; // dummy for compiler
  385.         }
  386.         cmd += val_buffer;
  387.     } else {
  388.         cmd += "NULL";
  389.     }
  390.     return true;
  391. }
  392. bool CTDS_RPCCmd::x_AssignOutputParams()
  393. {
  394.     char buffer[64];
  395.     for (unsigned int n = 0; n < m_Params.NofParams(); n++) {
  396.         if ((m_Params.GetParamStatus(n) & CDB_Params::fOutput) == 0)
  397.             continue;
  398.         const string& name  =  m_Params.GetParamName(n);
  399.         CDB_Object&   param = *m_Params.GetParam(n);
  400.         const char*   type;
  401.         string        cmd;
  402.         if (name.length() > kTDSMaxNameLen)
  403.             return false;
  404.         switch (param.GetType()) {
  405.         case eDB_Int:
  406.             type = "int";
  407.             break;
  408.         case eDB_SmallInt:
  409.             type = "smallint";
  410.             break;
  411.         case eDB_TinyInt:
  412.             type = "tinyint";
  413.             break;
  414.         case eDB_BigInt:
  415.             type = "numeric";
  416.             break;
  417.         case eDB_Char:
  418.         case eDB_VarChar:
  419.             type = "varchar(255)";
  420.             break;
  421. case eDB_LongChar: {
  422.     CDB_LongChar& lc = dynamic_cast<CDB_LongChar&> (param);
  423.     sprintf(buffer, "varchar(%d)", lc.Size());
  424.     type= buffer;
  425. break;
  426. }
  427.         case eDB_Binary:
  428.         case eDB_VarBinary:
  429.             type = "varbinary(255)";
  430.             break;
  431. case eDB_LongBinary: {
  432.     CDB_LongBinary& lb = dynamic_cast<CDB_LongBinary&> (param);
  433.     sprintf(buffer, "varbinary(%d)", lb.Size());
  434.     type= buffer;
  435. break;
  436. }
  437.         case eDB_Float:
  438.             type = "real";
  439.             break;
  440.         case eDB_Double:
  441.             type = "float";
  442.             break;
  443.         case eDB_SmallDateTime:
  444.             type = "smalldatetime";
  445.             break;
  446.         case eDB_DateTime:
  447.             type = "datetime";
  448.             break;            
  449.         default:
  450.             return false;
  451.         }
  452.         cmd += "declare " + name + ' ' + type + 'n';
  453.         if (!param.IsNULL()) {
  454.             cmd += "select " + name + " = ";
  455.             x_AddParamValue(cmd, param);
  456.             cmd+= 'n';
  457.         }
  458.         if (dbcmd(m_Cmd, (char*) cmd.c_str()) != SUCCEED)
  459.             return false;
  460.     }
  461.     return true;
  462. }
  463. bool CTDS_RPCCmd::x_AssignParams()
  464. {
  465.     for (unsigned int i = 0;  i < m_Params.NofParams();  i++) {
  466.       if(!m_Params.GetParamStatus(i)) continue;
  467.         CDB_Object& param = *m_Params.GetParam(i);
  468.         bool is_output =
  469.             (m_Params.GetParamStatus(i) & CDB_Params::fOutput) != 0;
  470.         const string& name  = m_Params.GetParamName(i);
  471.         string cmd= i? ", " : " ";
  472.         if(!name.empty()) {
  473.             cmd+= name + '=';
  474.             if(is_output) {
  475.                 cmd+= name + " out";
  476.             }
  477.             else {
  478.                 x_AddParamValue(cmd, param);
  479.             }
  480.         }
  481.         else {
  482.             x_AddParamValue(cmd, param);
  483.         }
  484.         if (dbcmd(m_Cmd, (char*) cmd.c_str()) != SUCCEED)
  485.             return false;
  486.     }
  487.     return true;
  488. }
  489. END_NCBI_SCOPE
  490. /*
  491.  * ===========================================================================
  492.  * $Log: rpc.cpp,v $
  493.  * Revision 1000.1  2004/06/01 19:20:58  gouriano
  494.  * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.12
  495.  *
  496.  * Revision 1.12  2004/05/17 21:13:37  gorelenk
  497.  * Added include of PCH ncbi_pch.hpp
  498.  *
  499.  * Revision 1.11  2003/08/13 18:04:05  soussov
  500.  * fixes copy/paste bug for DateTime
  501.  *
  502.  * Revision 1.10  2003/06/05 16:01:40  soussov
  503.  * adds code for DumpResults and for the dumped results processing
  504.  *
  505.  * Revision 1.9  2003/04/29 21:15:03  soussov
  506.  * new datatypes CDB_LongChar and CDB_LongBinary added
  507.  *
  508.  * Revision 1.8  2002/11/20 20:36:09  soussov
  509.  * fixed bug in parameters assignment
  510.  *
  511.  * Revision 1.7  2002/07/22 20:11:07  soussov
  512.  * fixes the RowCount calculations
  513.  *
  514.  * Revision 1.6  2002/02/22 22:12:45  soussov
  515.  * fixes bug with return params result
  516.  *
  517.  * Revision 1.5  2002/01/14 20:38:49  soussov
  518.  * timeout support for tds added
  519.  *
  520.  * Revision 1.4  2001/12/18 19:29:08  soussov
  521.  * adds conversion from nanosecs to milisecs for datetime args
  522.  *
  523.  * Revision 1.3  2001/12/18 16:42:44  soussov
  524.  * fixes bug in datetime argument processing
  525.  *
  526.  * Revision 1.2  2001/12/13 23:40:53  soussov
  527.  * changes double quotes to single quotes in SQL queries
  528.  *
  529.  * Revision 1.1  2001/10/25 00:39:22  vakatov
  530.  * Initial revision
  531.  *
  532.  * Revision 1.2  2001/10/22 16:28:02  lavr
  533.  * Default argument values removed
  534.  * (mistakenly left while moving code from header files)
  535.  *
  536.  * Revision 1.1  2001/10/22 15:19:56  lavr
  537.  * This is a major revamp (by Anton Lavrentiev, with help from Vladimir
  538.  * Soussov and Denis Vakatov) of the DBAPI "driver" libs originally
  539.  * written by Vladimir Soussov. The revamp follows the one of CTLib
  540.  * driver, and it involved massive code shuffling and grooming, numerous
  541.  * local API redesigns, adding comments and incorporating DBAPI to
  542.  * the C++ Toolkit.
  543.  *
  544.  * ===========================================================================
  545.  */