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

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: rpc.cpp,v $
  4.  * PRODUCTION Revision 1000.3  2004/06/01 19:21:56  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.9
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /* $Id: rpc.cpp,v 1000.3 2004/06/01 19:21:56 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 RPC command
  37.  *
  38.  */
  39.  
  40. #include <ncbi_pch.hpp>
  41. #include <dbapi/driver/odbc/interfaces.hpp>
  42. #include <dbapi/driver/util/numeric_convert.hpp>
  43. #include <stdio.h>
  44. BEGIN_NCBI_SCOPE
  45. /////////////////////////////////////////////////////////////////////////////
  46. //
  47. //  CODBC_RPCCmd::
  48. //
  49. CODBC_RPCCmd::CODBC_RPCCmd(CODBC_Connection* con, SQLHSTMT cmd,
  50.                          const string& proc_name, unsigned int nof_params) :
  51.     m_Connect(con), m_Cmd(cmd), m_Query(proc_name), m_Params(nof_params),
  52.     m_WasSent(false), m_HasFailed(false), m_Recompile(false), m_Res(0),
  53.     m_RowCount(-1), m_Reporter(&con->m_MsgHandlers, SQL_HANDLE_STMT, cmd)
  54. {
  55.     return;
  56. }
  57. bool CODBC_RPCCmd::BindParam(const string& param_name,
  58.                             CDB_Object* param_ptr, bool out_param)
  59. {
  60.     return m_Params.BindParam(CDB_Params::kNoParamNumber, param_name,
  61.                               param_ptr, out_param);
  62. }
  63. bool CODBC_RPCCmd::SetParam(const string& param_name,
  64.                            CDB_Object* param_ptr, bool out_param)
  65. {
  66.     return m_Params.SetParam(CDB_Params::kNoParamNumber, param_name,
  67.                              param_ptr, out_param);
  68. }
  69. bool CODBC_RPCCmd::Send()
  70. {
  71.     if (m_WasSent)
  72.         Cancel();
  73.     m_HasFailed = false;
  74.     m_HasStatus = false;
  75.     // make a language command
  76.     string main_exec_query("declare @STpROCrETURNsTATUS int;nexec @STpROCrETURNsTATUS=");
  77.     main_exec_query+= m_Query;
  78.     string param_result_query;
  79.     CMemPot bindGuard;
  80.     string q_str;
  81. if(m_Params.NofParams() > 0) {
  82. SQLINTEGER* indicator= (SQLINTEGER*)
  83. bindGuard.Alloc(m_Params.NofParams()*sizeof(SQLINTEGER));
  84. if (!x_AssignParams(q_str, main_exec_query, param_result_query, 
  85.                           bindGuard, indicator)) {
  86. SQLFreeStmt(m_Cmd, SQL_RESET_PARAMS);
  87. m_HasFailed = true;
  88. throw CDB_ClientEx(eDB_Error, 420003, "CODBC_RPCCmd::Send",
  89.                            "cannot assign params");
  90. }
  91. }
  92.    if(m_Recompile) main_exec_query+= " with recompile";
  93.    q_str+= main_exec_query + ";nselect STpROCrETURNsTATUS=@STpROCrETURNsTATUS";
  94.    if(!param_result_query.empty()) {
  95.        q_str+= ";nselect " + param_result_query;
  96.    }
  97.     switch(SQLExecDirect(m_Cmd, (SQLCHAR*)q_str.c_str(), SQL_NTS)) {
  98.     case SQL_SUCCESS:
  99.         m_hasResults= true;
  100.         break;
  101.     case SQL_NO_DATA:
  102.         m_hasResults= true; /* this is a bug in SQLExecDirect it returns SQL_NO_DATA if
  103.                                status result is the only result of RPC */
  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_RPCCmd::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_RPCCmd::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_RPCCmd::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_RPCCmd::Send",
  133.                            "Unexpected error");
  134.         
  135.     }
  136.     m_WasSent = true;
  137.     return true;
  138. }
  139. bool CODBC_RPCCmd::WasSent() const
  140. {
  141.     return m_WasSent;
  142. }
  143. bool CODBC_RPCCmd::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_RPCCmd::WasCanceled() const
  163. {
  164.     return !m_WasSent;
  165. }
  166. CDB_Result* CODBC_RPCCmd::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_RPCCmd::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.     char n_buff[64];
  183.     while(m_hasResults) {
  184.         switch(SQLNumResultCols(m_Cmd, &nof_cols)) {
  185.         case SQL_SUCCESS_WITH_INFO:
  186.             m_Reporter.ReportErrors();
  187.         case SQL_SUCCESS:
  188.             break;
  189.         case SQL_ERROR:
  190.             m_Reporter.ReportErrors();
  191.             throw CDB_ClientEx(eDB_Error, 420011, "CODBC_RPCCmd::Result",
  192.                                "SQLNumResultCols failed");
  193.         default:
  194.             throw CDB_ClientEx(eDB_Error, 420012, "CODBC_RPCCmd::Result",
  195.                                "SQLNumResultCols failed (memory corruption suspected)");
  196.         }
  197.         if(nof_cols < 1) { // no data in this result set
  198. SQLINTEGER rc;
  199. switch(SQLRowCount(m_Cmd, &rc)) {
  200. case SQL_SUCCESS_WITH_INFO:
  201. m_Reporter.ReportErrors(); 
  202. case SQL_SUCCESS: break;
  203. case SQL_ERROR:
  204. m_Reporter.ReportErrors();
  205. throw CDB_ClientEx(eDB_Error, 420013, "CODBC_RPCCmd::Result",
  206.                                "SQLRowCount failed");
  207. default:
  208. throw CDB_ClientEx(eDB_Error, 420014, "CODBC_RPCCmd::Result",
  209. "SQLRowCount failed (memory corruption suspected)");
  210. }
  211.             m_RowCount = rc;
  212.             m_hasResults= xCheck4MoreResults();
  213.             continue;
  214.         }
  215.         if(nof_cols == 1) { // it could be a status result
  216.             SQLSMALLINT l;
  217.             switch(SQLColAttribute(m_Cmd, 1, SQL_DESC_LABEL, n_buff, 64, &l, 0)) {
  218.             case SQL_SUCCESS_WITH_INFO: m_Reporter.ReportErrors();
  219.             case SQL_SUCCESS:           break;
  220.             case SQL_ERROR:
  221.                 m_Reporter.ReportErrors();
  222.                 throw CDB_ClientEx(eDB_Error, 420015, "CODBC_RPCCmd::Result",
  223.                                    "SQLColAttribute failed");
  224.             default:
  225.                 throw CDB_ClientEx(eDB_Error, 420016, "CODBC_RPCCmd::Result",
  226.                                    "SQLColAttribute failed (memory corruption suspected)");
  227.             }
  228.             
  229.             if(strcmp(n_buff, "STpROCrETURNsTATUS") == 0) {//this is a status result
  230.                 m_HasStatus= true;
  231.                 m_Res= new CODBC_StatusResult(m_Cmd, m_Reporter);
  232.             }
  233.         }
  234. if(!m_Res) {
  235. if(m_HasStatus) {
  236. m_HasStatus= false;
  237. m_Res= new CODBC_ParamResult(nof_cols, m_Cmd, m_Reporter);
  238. }
  239. else {
  240. m_Res = new CODBC_RowResult(nof_cols, m_Cmd, m_Reporter);
  241. }
  242. }
  243. return Create_Result(*m_Res);
  244.     }
  245.     m_WasSent = false;
  246.     return 0;
  247. }
  248. bool CODBC_RPCCmd::HasMoreResults() const
  249. {
  250.     return m_hasResults;
  251. }
  252. void CODBC_RPCCmd::DumpResults()
  253. {
  254.     CDB_Result* dbres;
  255.     while(m_WasSent) {
  256.         dbres= Result();
  257.         if(dbres) {
  258.             if(m_Connect->m_ResProc) {
  259.                 m_Connect->m_ResProc->ProcessResult(*dbres);
  260.             }
  261.             else {
  262.                 while(dbres->Fetch());
  263.             }
  264.             delete dbres;
  265.         }
  266.     }
  267. }
  268. bool CODBC_RPCCmd::HasFailed() const
  269. {
  270.     return m_HasFailed;
  271. }
  272. int CODBC_RPCCmd::RowCount() const
  273. {
  274.     return m_RowCount;
  275. }
  276. void CODBC_RPCCmd::SetRecompile(bool recompile)
  277. {
  278.     m_Recompile = recompile;
  279. }
  280. void CODBC_RPCCmd::Release()
  281. {
  282.     m_BR = 0;
  283.     if (m_WasSent) {
  284.         Cancel();
  285.         m_WasSent = false;
  286.     }
  287.     m_Connect->DropCmd(*this);
  288.     delete this;
  289. }
  290. CODBC_RPCCmd::~CODBC_RPCCmd()
  291. {
  292.     if (m_BR)
  293.         *m_BR = 0;
  294.     if (m_WasSent)
  295.         Cancel();
  296.     SQLFreeHandle(SQL_HANDLE_STMT, m_Cmd);
  297. }
  298. bool CODBC_RPCCmd::x_AssignParams(string& cmd, string& q_exec, string& q_select,
  299.                                    CMemPot& bind_guard, SQLINTEGER* indicator)
  300. {
  301.     char p_nm[16], tbuf[32];
  302.     // check if we do have a named parameters (first named - all named)
  303.     bool param_named= !m_Params.GetParamName(0).empty();
  304.     for (unsigned int n = 0; n < m_Params.NofParams(); n++) {
  305.         if(m_Params.GetParamStatus(n) == 0) continue;
  306.         const string& name  =  m_Params.GetParamName(n);
  307.         CDB_Object&   param = *m_Params.GetParam(n);
  308.         const char*   type;
  309.         switch (param.GetType()) {
  310.         case eDB_Int: {
  311.             CDB_Int& val = dynamic_cast<CDB_Int&> (param);
  312.             type = "int";
  313.             indicator[n]= 4;
  314.             SQLBindParameter(m_Cmd, n+1, SQL_PARAM_INPUT, SQL_C_SLONG, 
  315.                              SQL_INTEGER, 4, 0, val.BindVal(), 4, indicator+n);
  316.             break;
  317.         }
  318.         case eDB_SmallInt: {
  319.             CDB_SmallInt& val = dynamic_cast<CDB_SmallInt&> (param);
  320.             type = "smallint";
  321.             indicator[n]= 2;
  322.             SQLBindParameter(m_Cmd, n+1, SQL_PARAM_INPUT, SQL_C_SSHORT, 
  323.                              SQL_SMALLINT, 2, 0, val.BindVal(), 2, indicator+n);
  324.             break;
  325.         }
  326.         case eDB_TinyInt: {
  327.             CDB_TinyInt& val = dynamic_cast<CDB_TinyInt&> (param);
  328.             type = "tinyint";
  329.             indicator[n]= 1;
  330.             SQLBindParameter(m_Cmd, n+1, SQL_PARAM_INPUT, SQL_C_UTINYINT, 
  331.                              SQL_TINYINT, 1, 0, val.BindVal(), 1, indicator+n);
  332.             break;
  333.         }
  334.         case eDB_BigInt: {
  335.             CDB_BigInt& val = dynamic_cast<CDB_BigInt&> (param);
  336.             type = "numeric";
  337.             indicator[n]= 8;
  338.             SQLBindParameter(m_Cmd, n+1, SQL_PARAM_INPUT, SQL_C_SBIGINT, 
  339.                              SQL_NUMERIC, 18, 0, val.BindVal(), 18, indicator+n);
  340.             
  341.             break;
  342.         }
  343.         case eDB_Char: {
  344.             CDB_Char& val = dynamic_cast<CDB_Char&> (param);
  345.             type= "varchar(255)";
  346.             indicator[n]= SQL_NTS;
  347.             SQLBindParameter(m_Cmd, n+1, SQL_PARAM_INPUT, SQL_C_CHAR, 
  348.                              SQL_VARCHAR, 255, 0, (void*)val.Value(), 256, indicator+n);
  349.             break;
  350.         }
  351.         case eDB_VarChar: {
  352.             CDB_VarChar& val = dynamic_cast<CDB_VarChar&> (param);
  353.             type = "varchar(255)";
  354.             indicator[n]= SQL_NTS;
  355.             SQLBindParameter(m_Cmd, n+1, SQL_PARAM_INPUT, SQL_C_CHAR, 
  356.                              SQL_VARCHAR, 255, 0, (void*)val.Value(), 256, indicator+n);
  357.             break;
  358.         }
  359.         case eDB_LongChar: {
  360.             CDB_LongChar& val = dynamic_cast<CDB_LongChar&> (param);
  361. sprintf(tbuf,"varchar(%d)", val.Size());
  362.             type= tbuf;
  363.             indicator[n]= SQL_NTS;
  364.             SQLBindParameter(m_Cmd, n+1, SQL_PARAM_INPUT, SQL_C_CHAR, 
  365.                              SQL_VARCHAR, val.Size(), 0, (void*)val.Value(), val.Size(), indicator+n);
  366.             break;
  367.         }
  368.         case eDB_Binary: {
  369.             CDB_Binary& val = dynamic_cast<CDB_Binary&> (param);
  370.             type = "varbinary(255)";
  371.             indicator[n]= val.Size();
  372.             SQLBindParameter(m_Cmd, n+1, SQL_PARAM_INPUT, SQL_C_BINARY, 
  373.                              SQL_VARBINARY, 255, 0, (void*)val.Value(), 255, indicator+n);
  374.             break;
  375.         }
  376.         case eDB_VarBinary: {
  377.             CDB_VarBinary& val = dynamic_cast<CDB_VarBinary&> (param);
  378.             type = "varbinary(255)";
  379.             indicator[n]= val.Size();
  380.             SQLBindParameter(m_Cmd, n+1, SQL_PARAM_INPUT, SQL_C_BINARY, 
  381.                              SQL_VARBINARY, 255, 0, (void*)val.Value(), 255, indicator+n);
  382.             break;
  383.         }
  384.         case eDB_LongBinary: {
  385.             CDB_LongBinary& val = dynamic_cast<CDB_LongBinary&> (param);
  386. sprintf(tbuf,"varbinary(%d)", val.Size());
  387.             type= tbuf;
  388.             indicator[n]= val.DataSize();
  389.             SQLBindParameter(m_Cmd, n+1, SQL_PARAM_INPUT, SQL_C_BINARY, 
  390.                              SQL_VARBINARY, val.Size(), 0, (void*)val.Value(), val.Size(), indicator+n);
  391.             break;
  392.         }
  393.         case eDB_Float: {
  394.             CDB_Float& val = dynamic_cast<CDB_Float&> (param);
  395.             type = "real";
  396.             indicator[n]= 4;
  397.             SQLBindParameter(m_Cmd, n+1, SQL_PARAM_INPUT, SQL_C_FLOAT, 
  398.                              SQL_REAL, 4, 0, val.BindVal(), 4, indicator+n);
  399.             break;
  400.         }
  401.         case eDB_Double: {
  402.             CDB_Double& val = dynamic_cast<CDB_Double&> (param);
  403.             type = "float";
  404.             indicator[n]= 8;
  405.             SQLBindParameter(m_Cmd, n+1, SQL_PARAM_INPUT, SQL_C_DOUBLE, 
  406.                              SQL_FLOAT, 8, 0, val.BindVal(), 8, indicator+n);
  407.             break;
  408.         }
  409.         case eDB_SmallDateTime: {
  410.             CDB_SmallDateTime& val = dynamic_cast<CDB_SmallDateTime&> (param);
  411.             type = "smalldatetime";
  412.             SQL_TIMESTAMP_STRUCT* ts= 0;
  413.             if(!val.IsNULL()) {
  414.                 ts= (SQL_TIMESTAMP_STRUCT*)bind_guard.Alloc(sizeof(SQL_TIMESTAMP_STRUCT));
  415.                 const CTime& t= val.Value();
  416.                 ts->year= t.Year();
  417.                 ts->month= t.Month();
  418.                 ts->day= t.Day();
  419.                 ts->hour= t.Hour();
  420.                 ts->minute= t.Minute();
  421.                 ts->second= 0;
  422.                 ts->fraction= 0;
  423.                 indicator[n]= sizeof(SQL_TIMESTAMP_STRUCT);
  424.             }
  425.             SQLBindParameter(m_Cmd, n+1, SQL_PARAM_INPUT, SQL_C_TYPE_TIMESTAMP, 
  426.                              SQL_TYPE_TIMESTAMP, 16, 0, (void*)ts, sizeof(SQL_TIMESTAMP_STRUCT), 
  427.                              indicator+n);
  428.             break;
  429.         }
  430.         case eDB_DateTime: {
  431.             CDB_DateTime& val = dynamic_cast<CDB_DateTime&> (param);
  432.             type = "datetime";
  433.             SQL_TIMESTAMP_STRUCT* ts= 0;
  434.             if(!val.IsNULL()) {
  435.                 ts= (SQL_TIMESTAMP_STRUCT*)bind_guard.Alloc(sizeof(SQL_TIMESTAMP_STRUCT));
  436.                 const CTime& t= val.Value();
  437.                 ts->year= t.Year();
  438.                 ts->month= t.Month();
  439.                 ts->day= t.Day();
  440.                 ts->hour= t.Hour();
  441.                 ts->minute= t.Minute();
  442.                 ts->second= t.Second();
  443.                 ts->fraction= t.NanoSecond()/1000000;
  444. ts->fraction*= 1000000; /* MSSQL has a bug - it can not handle fraction of msecs */
  445.                 indicator[n]= sizeof(SQL_TIMESTAMP_STRUCT);
  446.             }
  447.             SQLBindParameter(m_Cmd, n+1, SQL_PARAM_INPUT, SQL_C_TYPE_TIMESTAMP, 
  448.                              SQL_TYPE_TIMESTAMP, 23, 3, ts, sizeof(SQL_TIMESTAMP_STRUCT), 
  449.                              indicator+n);
  450.             break;
  451.         }
  452.         default:
  453.             return false;
  454.         }
  455.         q_exec+= n? ',':' ';
  456.         if(!param_named) {
  457.             sprintf(p_nm, "@pR%d", n);
  458.             q_exec+= p_nm;
  459.             cmd+= "declare ";
  460. cmd+= p_nm;
  461. cmd+= ' ';
  462. cmd+= type;
  463. cmd+= ";select ";
  464. cmd+= p_nm;
  465. cmd+= " = ?;";
  466.         }
  467.         else {
  468.             q_exec+= name+'='+name;
  469.             cmd += "declare " + name + ' ' + type + ";select " + name + " = ?;";
  470.         }
  471.         if(param.IsNULL()) {
  472.             indicator[n]= SQL_NULL_DATA;
  473.         }
  474.         if ((m_Params.GetParamStatus(n) & CDB_Params::fOutput) != 0) {
  475.             q_exec+= " output";
  476.             const char* p_name= param_named? name.c_str() : p_nm;
  477.             if(!q_select.empty()) q_select+= ',';
  478.             q_select.append(p_name+1);
  479.             q_select+= '=';
  480. q_select+= p_name;
  481.         }
  482.             
  483.     }
  484.     return true;
  485. }
  486. bool CODBC_RPCCmd::xCheck4MoreResults()
  487. {
  488.     switch(SQLMoreResults(m_Cmd)) {
  489.     case SQL_SUCCESS_WITH_INFO: m_Reporter.ReportErrors();
  490.     case SQL_SUCCESS:           return true;
  491.     case SQL_NO_DATA:           return false;
  492.     case SQL_ERROR:             
  493.         m_Reporter.ReportErrors();
  494.         throw CDB_ClientEx(eDB_Error, 420014, "CODBC_RPCCmd::xCheck4MoreResults",
  495.                            "SQLMoreResults failed");
  496.     default:
  497.         throw CDB_ClientEx(eDB_Error, 420015, "CODBC_RPCCmd::xCheck4MoreResults",
  498.                            "SQLMoreResults failed (memory corruption suspected)");
  499.     }
  500. }
  501. END_NCBI_SCOPE
  502. /*
  503.  * ===========================================================================
  504.  * $Log: rpc.cpp,v $
  505.  * Revision 1000.3  2004/06/01 19:21:56  gouriano
  506.  * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.9
  507.  *
  508.  * Revision 1.9  2004/05/17 21:16:06  gorelenk
  509.  * Added include of PCH ncbi_pch.hpp
  510.  *
  511.  * Revision 1.8  2004/01/27 18:00:07  soussov
  512.  * patches the SQLExecDirect bug
  513.  *
  514.  * Revision 1.7  2003/11/07 17:14:20  soussov
  515.  * work around the odbc bug. It can not handle properly the fractions of msecs
  516.  *
  517.  * Revision 1.6  2003/11/06 20:33:32  soussov
  518.  * fixed bug in DateTime bindings
  519.  *
  520.  * Revision 1.5  2003/06/05 16:02:04  soussov
  521.  * adds code for DumpResults and for the dumped results processing
  522.  *
  523.  * Revision 1.4  2003/05/16 20:26:44  soussov
  524.  * adds code to skip parameter if it was not set
  525.  *
  526.  * Revision 1.3  2003/05/08 20:30:24  soussov
  527.  * CDB_LongChar CDB_LongBinary added
  528.  *
  529.  * Revision 1.2  2003/05/05 20:48:47  ucko
  530.  * +<stdio.h> for sprintf
  531.  *
  532.  * Revision 1.1  2002/06/18 22:06:25  soussov
  533.  * initial commit
  534.  *
  535.  *
  536.  * ===========================================================================
  537.  */