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

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: lang_cmd.cpp,v $
  4.  * PRODUCTION Revision 1000.2  2004/06/01 19:21:51  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.8
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /* $Id: lang_cmd.cpp,v 1000.2 2004/06/01 19:21:51 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:  ODBC language command
  37.  *
  38.  */
  39. #include <ncbi_pch.hpp>
  40. #include <stdio.h>
  41. #include <dbapi/driver/odbc/interfaces.hpp>
  42. BEGIN_NCBI_SCOPE
  43. /////////////////////////////////////////////////////////////////////////////
  44. //
  45. //  CODBC_LangCmd::
  46. //
  47. CODBC_LangCmd::CODBC_LangCmd(CODBC_Connection* conn, SQLHSTMT cmd,
  48.                            const string& lang_query,
  49.                            unsigned int nof_params) :
  50.     m_Connect(conn), m_Cmd(cmd), m_Query(lang_query), m_Params(nof_params), 
  51.     m_Reporter(&conn->m_MsgHandlers, SQL_HANDLE_STMT, cmd)
  52. {
  53.     m_WasSent   =  false;
  54.     m_HasFailed =  false;
  55.     m_Res       =  0;
  56.     m_RowCount  = -1;
  57. }
  58. bool CODBC_LangCmd::More(const string& query_text)
  59. {
  60.     m_Query.append(query_text);
  61.     return true;
  62. }
  63. bool CODBC_LangCmd::BindParam(const string& param_name, CDB_Object* param_ptr)
  64. {
  65.     return
  66.         m_Params.BindParam(CDB_Params::kNoParamNumber, param_name, param_ptr);
  67. }
  68. bool CODBC_LangCmd::SetParam(const string& param_name, CDB_Object* param_ptr)
  69. {
  70.     return
  71.         m_Params.SetParam(CDB_Params::kNoParamNumber, param_name, param_ptr);
  72. }
  73. bool CODBC_LangCmd::Send()
  74. {
  75.     if (m_WasSent)
  76.         Cancel();
  77.     m_HasFailed = false;
  78.     CMemPot bindGuard;
  79.     string q_str;
  80. if(m_Params.NofParams() > 0) {
  81. SQLINTEGER* indicator= (SQLINTEGER*)
  82. bindGuard.Alloc(m_Params.NofParams()*sizeof(SQLINTEGER));
  83. if (!x_AssignParams(q_str, bindGuard, indicator)) {
  84. SQLFreeStmt(m_Cmd, SQL_RESET_PARAMS);
  85. m_HasFailed = true;
  86. throw CDB_ClientEx(eDB_Error, 420003, "CODBC_LangCmd::Send",
  87.                            "cannot assign params");
  88. }
  89. }
  90.     string* real_query;
  91.     if(!q_str.empty()) {
  92.         q_str.append(m_Query);
  93.         real_query= &q_str;
  94.     }
  95.     else {
  96.         real_query= &m_Query;
  97.     }
  98.     switch(SQLExecDirect(m_Cmd, (SQLCHAR*)real_query->c_str(), SQL_NTS)) {
  99.     case SQL_SUCCESS:
  100.         m_hasResults= true;
  101.         break;
  102.     case SQL_NO_DATA:
  103.         m_hasResults= false;
  104.         m_RowCount= 0;
  105.         break;
  106.     case SQL_ERROR:
  107.         m_Reporter.ReportErrors();
  108.         SQLFreeStmt(m_Cmd, SQL_RESET_PARAMS);
  109.         m_HasFailed = true;
  110.         throw CDB_ClientEx(eDB_Fatal, 420001, "CODBC_LangCmd::Send",
  111.                            "SQLExecDirect failed");
  112.     case SQL_SUCCESS_WITH_INFO:
  113.         m_Reporter.ReportErrors();
  114.         m_hasResults= true;
  115.         break;
  116.     case SQL_STILL_EXECUTING:
  117.         m_Reporter.ReportErrors();
  118.         SQLFreeStmt(m_Cmd, SQL_RESET_PARAMS);
  119.         m_HasFailed = true;
  120.         throw CDB_ClientEx(eDB_Fatal, 420002, "CODBC_LangCmd::Send",
  121.                            "Some other query is executing on this connection");
  122.         
  123.     case SQL_INVALID_HANDLE:
  124.         m_HasFailed= true;
  125.         throw CDB_ClientEx(eDB_Fatal, 420004, "CODBC_LangCmd::Send",
  126.                            "The statement handler is invalid (memory corruption suspected)");
  127.         
  128.     default:
  129.         m_Reporter.ReportErrors();
  130.         SQLFreeStmt(m_Cmd, SQL_RESET_PARAMS);
  131.         m_HasFailed = true;
  132.         throw CDB_ClientEx(eDB_Fatal, 420005, "CODBC_LangCmd::Send",
  133.                            "Unexpected error");
  134.         
  135.     }
  136.     m_WasSent = true;
  137.     return true;
  138. }
  139. bool CODBC_LangCmd::WasSent() const
  140. {
  141.     return m_WasSent;
  142. }
  143. bool CODBC_LangCmd::Cancel()
  144. {
  145.     if (m_WasSent) {
  146.         if (m_Res) {
  147.             delete m_Res;
  148.             m_Res = 0;
  149.         }
  150.         m_WasSent = false;
  151.         switch(SQLFreeStmt(m_Cmd, SQL_CLOSE)) {
  152.         case SQL_SUCCESS_WITH_INFO: m_Reporter.ReportErrors();
  153.         case SQL_SUCCESS:           break;
  154.         case SQL_ERROR:             m_Reporter.ReportErrors();
  155.         default:                    return false;
  156.         }
  157.     }
  158.     SQLFreeStmt(m_Cmd, SQL_RESET_PARAMS);
  159.     // m_Query.erase();
  160.     return true;
  161. }
  162. bool CODBC_LangCmd::WasCanceled() const
  163. {
  164.     return !m_WasSent;
  165. }
  166. CDB_Result* CODBC_LangCmd::Result()
  167. {
  168.     if (m_Res) {
  169.         delete m_Res;
  170.         m_Res = 0;
  171.         m_hasResults= xCheck4MoreResults();
  172.     }
  173.     if (!m_WasSent) {
  174.         throw CDB_ClientEx(eDB_Error, 420010, "CODBC_LangCmd::Result",
  175.                            "a command has to be sent first");
  176.     }
  177.     if(!m_hasResults) {
  178. m_WasSent= false;
  179.         return 0;
  180.     }
  181.     SQLSMALLINT nof_cols= 0;
  182.     while(m_hasResults) {
  183.         switch(SQLNumResultCols(m_Cmd, &nof_cols)) {
  184.         case SQL_SUCCESS_WITH_INFO:
  185.             m_Reporter.ReportErrors();
  186.         case SQL_SUCCESS:
  187.             break;
  188.         case SQL_ERROR:
  189.             m_Reporter.ReportErrors();
  190.             throw CDB_ClientEx(eDB_Error, 420011, "CODBC_LangCmd::Result",
  191.                                "SQLNumResultCols failed");
  192.         default:
  193.             throw CDB_ClientEx(eDB_Error, 420012, "CODBC_LangCmd::Result",
  194.                                "SQLNumResultCols failed (memory corruption suspected)");
  195.         }
  196.         if(nof_cols < 1) { // no data in this result set
  197. SQLINTEGER rc;
  198. switch(SQLRowCount(m_Cmd, &rc)) {
  199. case SQL_SUCCESS_WITH_INFO:
  200. m_Reporter.ReportErrors(); 
  201. case SQL_SUCCESS: break;
  202. case SQL_ERROR:
  203. m_Reporter.ReportErrors();
  204. throw CDB_ClientEx(eDB_Error, 420013, "CODBC_LangCmd::Result",
  205.                                "SQLRowCount failed");
  206. default:
  207. throw CDB_ClientEx(eDB_Error, 420014, "CODBC_LangCmd::Result",
  208. "SQLRowCount failed (memory corruption suspected)");
  209. }
  210.             m_RowCount = rc;
  211.             m_hasResults= xCheck4MoreResults();
  212.             continue;
  213.         }
  214.         m_Res = new CODBC_RowResult(nof_cols, m_Cmd, m_Reporter);
  215.         return Create_Result(*m_Res);
  216.     }
  217.     m_WasSent = false;
  218.     return 0;
  219. }
  220. bool CODBC_LangCmd::HasMoreResults() const
  221. {
  222.     return m_hasResults;
  223. }
  224. void CODBC_LangCmd::DumpResults()
  225. {
  226.     CDB_Result* dbres;
  227.     while(m_WasSent) {
  228.         dbres= Result();
  229.         if(dbres) {
  230.             if(m_Connect->m_ResProc) {
  231.                 m_Connect->m_ResProc->ProcessResult(*dbres);
  232.             }
  233.             else {
  234.                 while(dbres->Fetch());
  235.             }
  236.             delete dbres;
  237.         }
  238.     }
  239. }
  240. bool CODBC_LangCmd::HasFailed() const
  241. {
  242.     return m_HasFailed;
  243. }
  244. int CODBC_LangCmd::RowCount() const
  245. {
  246.     return m_RowCount;
  247. }
  248. void CODBC_LangCmd::Release()
  249. {
  250.     m_BR = 0;
  251.     if (m_WasSent) {
  252.         Cancel();
  253.         m_WasSent = false;
  254.     }
  255.     m_Connect->DropCmd(*this);
  256.     delete this;
  257. }
  258. CODBC_LangCmd::~CODBC_LangCmd()
  259. {
  260.     if (m_BR)
  261.         *m_BR = 0;
  262.     if (m_WasSent)
  263.         Cancel();
  264.     SQLFreeHandle(SQL_HANDLE_STMT, m_Cmd);
  265. }
  266. bool CODBC_LangCmd::x_AssignParams(string& cmd, CMemPot& bind_guard, SQLINTEGER* indicator)
  267. {
  268.     for (unsigned int n = 0; n < m_Params.NofParams(); n++) {
  269.         if(m_Params.GetParamStatus(n) == 0) continue;
  270.         const string& name  =  m_Params.GetParamName(n);
  271.         CDB_Object&   param = *m_Params.GetParam(n);
  272.         const char*   type;
  273. char tbuf[64];
  274. SQLRETURN rc_from_bind;
  275.         switch (param.GetType()) {
  276.         case eDB_Int: {
  277.             CDB_Int& val = dynamic_cast<CDB_Int&> (param);
  278.             type = "int";
  279.             indicator[n]= 4;
  280.             rc_from_bind= SQLBindParameter(m_Cmd, n+1, SQL_PARAM_INPUT, SQL_C_SLONG, 
  281.                              SQL_INTEGER, 4, 0, val.BindVal(), 4, indicator+n);
  282.             break;
  283.         }
  284.         case eDB_SmallInt: {
  285.             CDB_SmallInt& val = dynamic_cast<CDB_SmallInt&> (param);
  286.             type = "smallint";
  287.             indicator[n]= 2;
  288.             rc_from_bind= SQLBindParameter(m_Cmd, n+1, SQL_PARAM_INPUT, SQL_C_SSHORT, 
  289.                              SQL_SMALLINT, 2, 0, val.BindVal(), 2, indicator+n);
  290.             break;
  291.         }
  292.         case eDB_TinyInt: {
  293.             CDB_TinyInt& val = dynamic_cast<CDB_TinyInt&> (param);
  294.             type = "tinyint";
  295.             indicator[n]= 1;
  296.             rc_from_bind= SQLBindParameter(m_Cmd, n+1, SQL_PARAM_INPUT, SQL_C_UTINYINT, 
  297.                              SQL_TINYINT, 1, 0, val.BindVal(), 1, indicator+n);
  298.             break;
  299.         }
  300.         case eDB_BigInt: {
  301.             CDB_BigInt& val = dynamic_cast<CDB_BigInt&> (param);
  302.             type = "numeric";
  303.             indicator[n]= 8;
  304.             rc_from_bind= SQLBindParameter(m_Cmd, n+1, SQL_PARAM_INPUT, SQL_C_SBIGINT, 
  305.                              SQL_NUMERIC, 18, 0, val.BindVal(), 18, indicator+n);
  306.             
  307.             break;
  308.         }
  309.         case eDB_Char: {
  310.             CDB_Char& val = dynamic_cast<CDB_Char&> (param);
  311.             type= "varchar(255)";
  312.             indicator[n]= SQL_NTS;
  313.             rc_from_bind= SQLBindParameter(m_Cmd, n+1, SQL_PARAM_INPUT, SQL_C_CHAR, 
  314.                              SQL_VARCHAR, 255, 0, (void*)val.Value(), 256, indicator+n);
  315.             break;
  316.         }
  317.         case eDB_VarChar: {
  318.             CDB_VarChar& val = dynamic_cast<CDB_VarChar&> (param);
  319.             type = "varchar(255)";
  320.             indicator[n]= SQL_NTS;
  321.             rc_from_bind= SQLBindParameter(m_Cmd, n+1, SQL_PARAM_INPUT, SQL_C_CHAR, 
  322.                              SQL_VARCHAR, 255, 0, (void*)val.Value(), 256, indicator+n);
  323.             break;
  324.         }
  325.         case eDB_LongChar: {
  326.             CDB_LongChar& val = dynamic_cast<CDB_LongChar&> (param);
  327. sprintf(tbuf,"varchar(%d)", val.Size());
  328.             type= tbuf;
  329.             indicator[n]= SQL_NTS;
  330.             rc_from_bind= SQLBindParameter(m_Cmd, n+1, SQL_PARAM_INPUT, SQL_C_CHAR, 
  331.                              SQL_VARCHAR, val.Size(), 0, (void*)val.Value(), val.Size(), indicator+n);
  332.             break;
  333.         }
  334.         case eDB_Binary: {
  335.             CDB_Binary& val = dynamic_cast<CDB_Binary&> (param);
  336.             type = "varbinary(255)";
  337.             indicator[n]= val.Size();
  338.             rc_from_bind= SQLBindParameter(m_Cmd, n+1, SQL_PARAM_INPUT, SQL_C_BINARY, 
  339.                              SQL_VARBINARY, 255, 0, (void*)val.Value(), 255, indicator+n);
  340.             break;
  341.         }
  342.         case eDB_VarBinary: {
  343.             CDB_VarBinary& val = dynamic_cast<CDB_VarBinary&> (param);
  344.             type = "varbinary(255)";
  345.             indicator[n]= val.Size();
  346.             rc_from_bind= SQLBindParameter(m_Cmd, n+1, SQL_PARAM_INPUT, SQL_C_BINARY, 
  347.                              SQL_VARBINARY, 255, 0, (void*)val.Value(), 255, indicator+n);
  348.             break;
  349.         }
  350.         case eDB_LongBinary: {
  351.             CDB_LongBinary& val = dynamic_cast<CDB_LongBinary&> (param);
  352. sprintf(tbuf,"varbinary(%d)", val.Size());
  353.             type= tbuf;
  354.             type = "varbinary(255)";
  355.             indicator[n]= val.DataSize();
  356.             rc_from_bind= SQLBindParameter(m_Cmd, n+1, SQL_PARAM_INPUT, SQL_C_BINARY, 
  357.                              SQL_VARBINARY, val.Size(), 0, (void*)val.Value(), val.Size(), indicator+n);
  358.             break;
  359.         }
  360.         case eDB_Float: {
  361.             CDB_Float& val = dynamic_cast<CDB_Float&> (param);
  362.             type = "real";
  363.             indicator[n]= 4;
  364.             rc_from_bind= SQLBindParameter(m_Cmd, n+1, SQL_PARAM_INPUT, SQL_C_FLOAT, 
  365.                              SQL_REAL, 4, 0, val.BindVal(), 4, indicator+n);
  366.             break;
  367.         }
  368.         case eDB_Double: {
  369.             CDB_Double& val = dynamic_cast<CDB_Double&> (param);
  370.             type = "float";
  371.             indicator[n]= 8;
  372.             rc_from_bind= SQLBindParameter(m_Cmd, n+1, SQL_PARAM_INPUT, SQL_C_DOUBLE, 
  373.                              SQL_FLOAT, 8, 0, val.BindVal(), 8, indicator+n);
  374.             break;
  375.         }
  376.         case eDB_SmallDateTime: {
  377.             CDB_SmallDateTime& val = dynamic_cast<CDB_SmallDateTime&> (param);
  378.             type = "smalldatetime";
  379.             SQL_TIMESTAMP_STRUCT* ts= 0;
  380.             if(!val.IsNULL()) {
  381.                 ts= (SQL_TIMESTAMP_STRUCT*)bind_guard.Alloc(sizeof(SQL_TIMESTAMP_STRUCT));
  382.                 const CTime& t= val.Value();
  383.                 ts->year= t.Year();
  384.                 ts->month= t.Month();
  385.                 ts->day= t.Day();
  386.                 ts->hour= t.Hour();
  387.                 ts->minute= t.Minute();
  388.                 ts->second= 0;
  389.                 ts->fraction= 0;
  390.                 indicator[n]= sizeof(SQL_TIMESTAMP_STRUCT);
  391.             }
  392.             rc_from_bind= SQLBindParameter(m_Cmd, n+1, SQL_PARAM_INPUT, SQL_C_TYPE_TIMESTAMP, 
  393.                              SQL_TYPE_TIMESTAMP, 16, 0, (void*)ts, sizeof(SQL_TIMESTAMP_STRUCT), 
  394.                              indicator+n);
  395.             break;
  396.         }
  397.         case eDB_DateTime: {
  398.             CDB_DateTime& val = dynamic_cast<CDB_DateTime&> (param);
  399.             type = "datetime";
  400.             SQL_TIMESTAMP_STRUCT* ts= 0;
  401.             if(!val.IsNULL()) {
  402.                 ts= (SQL_TIMESTAMP_STRUCT*)bind_guard.Alloc(sizeof(SQL_TIMESTAMP_STRUCT));
  403.                 const CTime& t= val.Value();
  404.                 ts->year= t.Year();
  405.                 ts->month= t.Month();
  406.                 ts->day= t.Day();
  407.                 ts->hour= t.Hour();
  408.                 ts->minute= t.Minute();
  409.                 ts->second= t.Second();
  410.                 ts->fraction= t.NanoSecond()/1000000;
  411. ts->fraction*= 1000000; /* MSSQL has a bug - it can not handle fraction of msecs */
  412.                 indicator[n]= sizeof(SQL_TIMESTAMP_STRUCT);
  413.             }
  414.             rc_from_bind= SQLBindParameter(m_Cmd, n+1, SQL_PARAM_INPUT, SQL_C_TYPE_TIMESTAMP, 
  415.                              SQL_TYPE_TIMESTAMP, 23, 3, ts, sizeof(SQL_TIMESTAMP_STRUCT), 
  416.                              indicator+n);
  417.             break;
  418.         }
  419.         default:
  420.             return false;
  421.         }
  422. switch(rc_from_bind) {
  423.         case SQL_SUCCESS_WITH_INFO:
  424.         m_Reporter.ReportErrors();
  425. case SQL_SUCCESS:
  426. break;
  427. case SQL_ERROR:
  428. m_Reporter.ReportErrors();
  429. throw CDB_ClientEx(eDB_Error, 420066, "CODBC_LangCmd::x_AssignParams",
  430.                                "SQLBindParameter failed");
  431. default:
  432. throw CDB_ClientEx(eDB_Error, 420067, "CODBC_LangCmd::x_AssignParams",
  433.                                "SQLBindParameter failed (memory corruption suspected)");
  434. }
  435.         cmd += "declare " + name + ' ' + type + ";select " + name + " = ?;";
  436.         if(param.IsNULL()) {
  437.             indicator[n]= SQL_NULL_DATA;
  438.         }
  439.     }
  440.     return true;
  441. }
  442. bool CODBC_LangCmd::xCheck4MoreResults()
  443. {
  444.     switch(SQLMoreResults(m_Cmd)) {
  445.     case SQL_SUCCESS_WITH_INFO: m_Reporter.ReportErrors();
  446.     case SQL_SUCCESS:           return true;
  447.     case SQL_NO_DATA:           return false;
  448.     case SQL_ERROR:             
  449.         m_Reporter.ReportErrors();
  450.         throw CDB_ClientEx(eDB_Error, 420014, "CODBC_LangCmd::xCheck4MoreResults",
  451.                            "SQLMoreResults failed");
  452.     default:
  453.         throw CDB_ClientEx(eDB_Error, 420015, "CODBC_LangCmd::xCheck4MoreResults",
  454.                            "SQLMoreResults failed (memory corruption suspected)");
  455.     }
  456. }
  457. END_NCBI_SCOPE
  458. /*
  459.  * ===========================================================================
  460.  * $Log: lang_cmd.cpp,v $
  461.  * Revision 1000.2  2004/06/01 19:21:51  gouriano
  462.  * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.8
  463.  *
  464.  * Revision 1.8  2004/05/17 21:16:06  gorelenk
  465.  * Added include of PCH ncbi_pch.hpp
  466.  *
  467.  * Revision 1.7  2003/11/07 17:14:20  soussov
  468.  * work around the odbc bug. It can not handle properly the fractions of msecs
  469.  *
  470.  * Revision 1.6  2003/11/06 20:33:32  soussov
  471.  * fixed bug in DateTime bindings
  472.  *
  473.  * Revision 1.5  2003/06/05 16:02:04  soussov
  474.  * adds code for DumpResults and for the dumped results processing
  475.  *
  476.  * Revision 1.4  2003/05/16 20:26:44  soussov
  477.  * adds code to skip parameter if it was not set
  478.  *
  479.  * Revision 1.3  2003/05/08 20:40:08  soussov
  480.  * adds stdio.h for sprintf
  481.  *
  482.  * Revision 1.2  2003/05/08 20:30:24  soussov
  483.  * CDB_LongChar CDB_LongBinary added
  484.  *
  485.  * Revision 1.1  2002/06/18 22:06:24  soussov
  486.  * initial commit
  487.  *
  488.  *
  489.  * ===========================================================================
  490.  */